DockerHub の Automated Build を使ってみる

自分で作ったイメージをローカルでビルドしてもよいのですが、Pushしたらビルドしてくれるフローをサクッと作りたいなぁと思って調べていたところ、DockerHubのAutomated Build が使えそうなので、試してに使ってみました。 設定自体は非常に簡単でした。

Demoアプリ

  • 簡単なDemoアプリを使ってAutomated Buildの設定を試してみたいと思います。
    • System.getProperty() を使って実行環境のJavaのバージョンと、ベンダー、VMの種類を画面に表示するようなものを作成しました。
    • アクセス時刻も表示するようにしました。
  • Java, Spring MVC を使いました。
package com.example.demo;

import java.time.LocalDateTime;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class DemoController {

  @GetMapping("/")
  public String index (Model model) {

    model.addAttribute("time", LocalDateTime.now().toString());
    model.addAttribute("version", 
      System.getProperty("java.version")
      + ", "
      + System.getProperty("java.vendor")
      + ", "
      + System.getProperty("java.vm.name")
    );
    return "index";
  }
}
  • テンプレートエンジンはThymeleafを利用しています。
<!DOCTYPE HTM
<html xmlns:th="http://www.thymeleaf.org">
  <head>
    <title>Spring MVC: demo app</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  </head>
  <body>
    <p>
      DATA: <span th:text="${time}"></span>
    </p>
    <p>
      Java version: <span th:text="${version}"></span>
    </p>
  </body>
</html>
  • コードはこちらにおいてあります。

Dockerfile を作成

  • Docker はあまり触り慣れていなかったので、Spring公式のTutorialを参考に作成していきました。
  • 最初はローカルでビルドしたFat jar をCopyしてイメージを作成する方法で進めました。
FROM openjdk:11.0.4-jdk-slim
VOLUME /tmp
ARG JAR_FILE
COPY ${JAR_FILE} demo.jar
ENTRYPOINT ["java","-jar","/demo.jar"]
  • openjdk:11.0.4-jdk-slim を利用しました。
  • VOLUME /tmp はSpringBootがTomcat用のworkディレクトリを /tmp 配下にデフォルトで作成するために記載しています。(今回のDemoアプリだと不要ですが)
  • デモアプリのビルドを実行し、Dockerビルドします。
docker build ./ -t dockerhub-automated-build-demo --build-arg JAR_FILE=target/demo-0.0.1-SNAPSHOT.jar
  • コンテナを起動します。
docker run --rm -d -p 8080:8080 -t dockerhub-automated-build-demo
  • これで localhost:8080 にアクセスすると画面が表示されます。 f:id:darshuheider:20191104192450p:plain
  • この方法でも個人で遊ぶ分にはよいのですが、チームに配布するとかなったらアプリのビルドも含めてできた方がより移植性が高くていいなぁと思ったのと、Automated Buildだけで完結するようにしたかったので、何か他にいい方法がないか探しました。

Multi-Stage Build

  • Tutorialにも記載されている、Multi-Stage Buildという機能を使うと上手いことできそうだとわかりました。
  • Multi-Stage Buildとは、簡単に言ってしまえば1つのイメージを別のイメージへコピーできる機能のことです。
FROM openjdk:11.0.4-jdk-slim as build
WORKDIR /workspace/app

COPY mvnw .
COPY .mvn .mvn
COPY pom.xml .
COPY src src

RUN chmod +x mvnw && ./mvnw install -DskipTests
RUN mkdir -p target/dependency && (cd target/dependency; jar -xf ../*.jar)

FROM openjdk:11.0.4-jdk-slim
VOLUME /tmp

ARG DEPENDENCY=/workspace/app/target/dependency
COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF
COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app
ENTRYPOINT ["java","-cp","app:app/lib/*","com.example.demo.DemoApplication"]
  • 上の場合だと、1番目の FROM でアプリケーションのビルドを実行し、そのイメージを2番目の FROM 以降でコピーして利用しています。
  • 4つのレイヤに分かれていて、最後のレイヤはアプリのソースとconfigurationが含まれています。
  • targetディレクトリをイメージに含めていないので、ある程度最適化はされています。
  • tutorial を元に作成しましたが、 RUN chmod +x mvnw && ./mvnw install -DskipTests となっている部分は、tutorialでは RUN ./mvnw install -DskipTests となっていますが、Automated Build で動かした時に ./mvnw: Permission denied でエラーとなったので変えました。
  • ちなみにこのMulti-Stage Buildだとキャッシュとかないので、アプリのビルドのたびにライブラリとか全てダウンロードすることになるので、時間はかかってしまいます。

Automated Build の設定

  • Docker Hub の Account Setting から Linked Accounts を選択して、GitHubとConnectします。
  • Repositoryの画面からcreate repository を選択して今回のデモ用のリポジトリを作成します。
    • Build rule で細かいBuildのルールを設定できるようですが、今回はデフォルトの設定のままにしました。
  • create & build ボタンを押下して SUCCESS となればOKです。
  • 以降はGitHubにPushすると、DockerのBuildが自動で走るようになります。