Java - Spring Batchのjarをビルドした際にDockerイメージもビルドする(Gradle)

Spring Batchで作成した.jarをDockerコンテナとして実行したい事情があった。
Gradleのビルド時にイメージビルドまでまとめてできないかと調べが、情報が少なそうだったので書く。

環境

  • JDK: OpenJDK Runtime Environment Temurin-17.0.6+10 (build 17.0.6+10)
  • Spring Boot: 2.7.10
  • Spring Batch: 4.3.8
  • Gradle: 7.6.1
  • Docker: 23.0.1, build a5ee5b1dfc

やり方

build.gradleに、ビルド結果の.jarを含めてDockerイメージを作成するタスク定義を追加する。
以下3ファイルをコピペすれば動くはず。

./build.gradle
plugins {
  id 'java'
  id 'org.springframework.boot' version '2.7.10-SNAPSHOT'
  id 'io.spring.dependency-management' version '1.0.15.RELEASE'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'

repositories {
  mavenCentral()
  maven { url 'https://repo.spring.io/milestone' }
  maven { url 'https://repo.spring.io/snapshot' }
}

dependencies {
  implementation 'org.springframework.boot:spring-boot-starter-batch'
  runtimeOnly 'com.h2database:h2'
  compileOnly 'org.projectlombok:lombok'
  annotationProcessor 'org.projectlombok:lombok'

  testImplementation 'org.springframework.boot:spring-boot-starter-test'
  testImplementation 'org.springframework.batch:spring-batch-test'
}

+ // buildタスクの実行後、生成された.jarをDockerイメージビルド用にコピーする。
+ // ./build/libs配下に置いたままイメージビルドするとビルドコンテキストが
+ // 大きくなってしまったりignoreを書くのが面倒だったりなので。
+ build.doLast {
+   copy {
+     from "./build/libs/demo-0.0.1-SNAPSHOT.jar"
+     into "./docker/"
+     rename "demo-0.0.1-SNAPSHOT.jar", "demo.jar"
+   }
+   // jarビルド時にDockerイメージのビルドも一緒にやってしまった方が楽な場合もあるかもしれない。
+   // exec {
+   //   executable 'sh'
+   //   args '-c', 'docker build -t sample_img -f ./docker/Dockerfile ./docker/'
+   // }
+ }

+ clean.doFirst {
+   delete './docker/demo.jar'
+ }

+ // Dockerイメージビルドタスク
+ task docker(type: Exec) {
+   executable 'sh'
+   args '-c', 'docker build -t sample_img -f ./docker/Dockerfile ./docker/'
+ }
+ docker.dependsOn build

tasks.named('test') {
  useJUnitPlatform()
}
./src/main/java/com/example/demo/SampleJobConfig.java
package com.example.demo;

import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import lombok.extern.slf4j.Slf4j;

/**
 * 実行時の引数「nanika」の内容をログ出力するJob.
 * nanikaが指定されない場合は「デフォルト値です!」をログ出力する.
 */
@Configuration
@EnableBatchProcessing
@Slf4j
public class SampleJobConfig {
  @Autowired
  public JobBuilderFactory jobFactory;

  @Autowired
  public StepBuilderFactory stepFactory;

  @Value("${nanika:デフォルト値です!}")
  private String nanika;

  @Bean
  public Job sampleJob(Step sampleStep1) {
    return jobFactory
      .get("sampleJob")
      .incrementer(new RunIdIncrementer())
      .start(sampleStep1)
      .build();
  }

  @Bean
  public Step sampleStep1() {
    return stepFactory
      .get("sampleStep1")
      .tasklet((contrib, context) -> {
        log.warn(nanika);
        return RepeatStatus.FINISHED;
      })
      .build();
  }

}
./docker/Dockerfile
FROM eclipse-temurin:17.0.4.1_1-jre-jammy
RUN addgroup --system spring \
  && adduser --system spring \
  && usermod -aG spring spring
USER spring:spring

COPY ./demo.jar demo.jar
ENTRYPOINT ["java", "-jar", "/demo.jar"]

jarとDockerイメージのビルド

Gradleでdockerタスクを実行すれば、jarのビルドからDockerイメージの作成までやってくれる。

./gradlew docker

Dockerコンテナ実行

実行すると標準出力の警告ログに「なんらかのパラメータ」が表示されるはず。

docker run --rm sample_img --nanika=なんらかのパラメータ