Edited at

Javaアプリの軽量コンテナイメージのつくりかた

More than 1 year has passed since last update.

JavaのプロダクトでDockerイメージを作る場合、docker build時にmaven実行してもよいのですが、時間がかかるし、runtimeで必要のないアーティファクトもダウンロードされるので、イメージが大きくなってしまいます。

そこで、CircleCIでビルドして、作ったJarをダウンロードして実行するDockerfileにすると楽ちんでビルドも速くイメージサイズも小さくすみます。


Uber JAR or Zipを作る

依存ライブラリも全部含めたJarを作るには以下のようにshadeプラグインを使うと簡単です。ManifestResourceTransformerを使ってmainClassをMANIFESTファイルに含むようにすれば実行可能Jarにもなります。


pom.xml

<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のところ)だけ追加します。


.circleci/config.yml

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では、このアーティファクトをダウンロードして実行するように書きます。


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を使っています。