Dockerで運用しているSpring Bootでできたwebアプリに、あらたにバッチ処理が必要になった。
webアプリと同じサーバで実行するので、同一のjarでwebアプリもバッチ処理も行えるようにしてみた。
仕組みとしては、javaコマンドでjarを実行するときに目的のAppクラスを指定出来るようになっている。
ビルドの設定
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>sandbox.Entrypoint</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<classifier>exec</classifier>
</configuration>
</plugin>
</plugins>
</build>
mavenでjarをビルドする時に、javaコマンドで実行されるクラスが指定する。
このクラスで、引数に応じて目的のAppクラスを切り替えられるようにする。
アプリの基底クラス
@Configuration
public abstract class AppBase {
@Autowired
DataSource dataSource;
@Autowired
Dialect dialect;
@Autowired
Naming naming;
}
webアプリ/バッチ処理で共通して利用するデータソースの設定などを行う。
webアプリ
@EnableAutoConfiguration
@ComponentScan
public class WebApp extends AppBase {
public static void main(String[] args) {
SpringApplication.run(WebApp.class, args);
}
}
元のAppクラスから、わかりやすいように名称を変更した。
特に変わったことは行わない。
バッチ処理
@EnableBatchProcessing
@EnableAutoConfiguration
@ComponentScan
public class Batch extends AppBase {
@Autowired
JobBuilderFactory jobBuilderFactory;
@Autowired
StepBuilderFactory stepBuilderFactory;
@Autowired
Crawler crawler;
public static void main(String[] args) {
SpringApplication application = new SpringApplication(Batch.class);
application.setWebEnvironment(false);
System.exit(SpringApplication.exit(application.run(args)));
}
@Bean
public Step crawl() {
return stepBuilderFactory.get("crawl").tasklet(new Tasklet() {
public RepeatStatus execute(StepContribution stepContribution,
ChunkContext chunkContext) throws Exception {
crawler.crawl();
return RepeatStatus.FINISHED;
}
}).build();
}
@Bean
public Job job(Step crawl) throws Exception {
return jobBuilderFactory.get("site-crawl")
.incrementer(new RunIdIncrementer()).start(crawl).build();
}
}
新たに実装したAppクラス。
実行時に不要なTomcatが起動しないようにしている。
エンドポイント
public class Entrypoint {
public static void main(String[] args) throws Exception {
if (args != null && args.length > 0 && "web".equals(args[0])) {
WebApp.main(args);
return;
}
Batch.main(args);
}
}
引数に応じて目的のAppクラスを切り替えるクラス。
第1引数が「web」の場合にwebアプリを実行するように定義。
新たなバッチ処理が増えた場合は、この引数のパターンを増やして対処が出来ると思う。
Docker
FROM frolvlad/alpine-oraclejdk8:slim
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/var/app.jar"]
イメージを作成するDockerfileではjarの実行を指定するのみ。
実行
Dockerを実行するサーバの/var/xxx.jarへ、avenでビルドしたjarを配置する。
docker run --name site-crawler-web \
-d \
-v /etc/localtime:/etc/localtime:ro \
-v /var/xxx.jar:/var/app.jar \
-p 80:8080 \
container \
web
webアプリを実行するときは、引数に「web」を指定する。
docker run --name site-crawler-batch \
-d \
-v /etc/localtime:/etc/localtime:ro \
-v /var/xxx.jar:/var/app.jar \
container \
batch
バッチを実行するときは、引数に「batch」(「web」以外)を指定する。
バッチ処理が終わるとコンテナが終了する。