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

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

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.