JavaのプロダクトでDockerイメージを作る場合、docker build
時にmaven実行してもよいのですが、時間がかかるし、runtimeで必要のないアーティファクトもダウンロードされるので、イメージが大きくなってしまいます。
そこで、CircleCIでビルドして、作ったJarをダウンロードして実行するDockerfileにすると楽ちんでビルドも速くイメージサイズも小さくすみます。
Uber JAR or Zipを作る
依存ライブラリも全部含めたJarを作るには以下のようにshadeプラグインを使うと簡単です。ManifestResourceTransformer
を使ってmainClassをMANIFESTファイルに含むようにすれば実行可能Jarにもなります。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>xxx.Main</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
assemblyプラグイン使ってzipファイルを作ってもよいかと思います。
circleciの設定を書く
CircleCI 2.0はpom.xmlをキャッシュキーとしてビルドコンテナを作るので、pomを書き換えない限り、高速にビルドできます。またMavenのリポジトリはCircleCIでミラーされているので、依存ライブラリのダウンロードも高速です。
ビルドの設定は、プロジェクト直下に.circleci/config.yml
を作っておきます。GitHubプロジェクトと連携されるときにサンプルが表示されるので、だいたいそのままで使えますが、最後にUber JARまたはZIPをArtifactにアップロードするステップ(下記例だとstore_artifacts
のところ)だけ追加します。
version: 2
jobs:
build:
docker:
- image: circleci/openjdk:8-jdk
working_directory: ~/repo
environment:
MAVEN_OPTS: -Xmx3200m
steps:
- checkout
- restore_cache:
keys:
- v1-dependencies-{{ checksum "pom.xml" }}
- v1-dependencies-
- run: mvn dependency:go-offline
- save_cache:
paths:
- ~/.m2
key: v1-dependencies-{{ checksum "pom.xml" }}
- run: mvn integration-test
- store_artifacts:
path: target/xxx-0.1.0-SNAPSHOT.jar
Dockerfieを作る
Dockerfileでは、このアーティファクトをダウンロードして実行するように書きます。
FROM openjdk:8-alpine
RUN apk --no-cache add curl jq
RUN curl 'https://circleci.com/api/v1.1/project/github/kawasima/xxx/latest/artifacts?branch=develop&filter=successful' \
| jq 'map(select(.["path"] == "home/circleci/repo/target/xxx-0.1.0-SNAPSHOT.jar"))' \
| jq '.[0]["url"]' \
| xargs curl -o xxx.jar
RUN apk del --purge curl jq
ENTRYPOINT ["java", "-jar", "xxx.jar"]
最後にビルドが成功したアーティファクトのURLは、Publicリポジトリの場合、CircleCI API v1.1を使って、認証なしで取得できます。JSONからアーティファクトを特定し、URLを抜き出すのにはjqを使っています。