DockerHub の Automated Build を使ってみる
自分で作ったイメージをローカルでビルドしてもよいのですが、Pushしたらビルドしてくれるフローをサクッと作りたいなぁと思って調べていたところ、DockerHubのAutomated Build が使えそうなので、試してに使ってみました。 設定自体は非常に簡単でした。
Demoアプリ
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
にアクセスすると画面が表示されます。 - この方法でも個人で遊ぶ分にはよいのですが、チームに配布するとかなったらアプリのビルドも含めてできた方がより移植性が高くていいなぁと思ったのと、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だとキャッシュとかないので、アプリのビルドのたびにライブラリとか全てダウンロードすることになるので、時間はかかってしまいます。