Cloud Native Buildpacksのpack CLIでSpring BootのFat Jarを起動するDocker Imageを作成する。 あるいはSpring Boot 2.3.0.M1 のlayeredをエミュレートする
この記事の内容
- pack CLIでLayer ArchitectのSpring Boot ApplicationのDocker Imageを作成する
- 上記の目的のために、Spring Boot 2.3.0.M1のlayered()をエミュレートしたshell scriptを書く
- 実用性皆無のネタ記事です 😑
Spring Boot 2.3.0.M1のBuildpacks サポートについて
Spring Boot 2.3.0.M1から、maven, gradleにデフォルトでDocker Imageを作成する機能が追加されました。
gradlew buildBootImage
で簡単にDocker Imageが作成できます。こりゃ便利。
Layered Jarについて
Layer Architect, Clean Architectを採用しているApplicationの場合、
bootJarに layered()
をつけてImageを作成します。記事を読む限り、Fat Jarを一旦解凍して再配置しているようです。
とにかく、Spring Boot 2.3 以降はDocker Imageをお手軽に作れるようになりそうです。
Spring Boot 2.2でもCloud Native Buildpacksを使いたいんじゃ!
という場合、pack CLIでimageを作成できます。
しかし、pack CLIにはデフォルトでFat Jarを使ったImageを作成する機能がないっぽいので、Clean ArchitectなApplicationの場合、普通に動きません 😑
(cf CLIならなんとかなるかもしれませんが、cloudFoundry使っていないので試せない)
とはいえ、Spring Boot 2.3.0.M1も結局はbuildpacksを使っているはずなので、頑張ればなんとかなるはず。
Spring Boot 2.3.0.M1のlayerToolsをエミュレートする
Spring Boot 2.3.0.M1で作成するImageと同じ感じにApplicationを配置すれば勝手に動くだろ、
という悪魔的な推測を元に、layerToolsをエミュレートするカジュアルなshを書きました。
Jibの実験で使っていたLayer ArchitectのApplicationをターゲットにしています。
#!/bin/bash # layers.sh TARGET_DIR="docker-app-web/build/libs" WORK_DIR="build/workspace" # build ./gradlew bootJar # jar解凍 mkdir -p $WORK_DIR cd $WORK_DIR jar xf ../../$TARGET_DIR/docker-app-web-0.0.1-SNAPSHOT.jar cd ../../ # layers directory mkdir -p $WORK_DIR/BOOT-INF/layers/application mkdir -p $WORK_DIR/BOOT-INF/layers/dependencies mkdir -p $WORK_DIR/BOOT-INF/layers/snapshot-dependencies # MANIFEST.MFを書き換える head -n 4 $WORK_DIR/META-INF/MANIFEST.MF | nkf -Lu > $WORK_DIR/META-INF/NEW_MANIFEST.MF echo "Spring-Boot-Layers-Index: BOOT-INF/layers.idx" >> $WORK_DIR/META-INF/NEW_MANIFEST.MF echo "Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx" >> $WORK_DIR/META-INF/NEW_MANIFEST.MF mv -f $WORK_DIR/META-INF/NEW_MANIFEST.MF $WORK_DIR/META-INF/MANIFEST.MF # 依存jarをmv find $WORK_DIR/BOOT-INF/lib -name "*SNAPSHOT.jar" | xargs -I% mv % $WORK_DIR/BOOT-INF/layers/snapshot-dependencies/ mv $WORK_DIR/BOOT-INF/lib/* $WORK_DIR/BOOT-INF/layers/dependencies rmdir $WORK_DIR/BOOT-INF/lib # main-class copy mv $WORK_DIR/BOOT-INF/classes $WORK_DIR/BOOT-INF/layers/application/ # classpath.idx作成 find $WORK_DIR/BOOT-INF/layers/snapshot-dependencies -name "*.jar" | sed -e 's/build\/workspace\///' > $WORK_DIR/BOOT-INF/classpath.idx find $WORK_DIR/BOOT-INF/layers/dependencies -name "*.jar" | sed -e 's/build\/workspace\///' >> $WORK_DIR/BOOT-INF/classpath.idx # layers.idx作成 echo "snapshot-dependencies" > $WORK_DIR/BOOT-INF/layers.idx echo "dependencies" >> $WORK_DIR/BOOT-INF/layers.idx echo "resources" >> $WORK_DIR/BOOT-INF/layers.idx echo "application" >> $WORK_DIR/BOOT-INF/layers.idx echo "layered!!"
これで、
pack build docker-app-buildpacks:0.0.1-SNAPSHOT --builder cloudfoundry/cnb:bionic --path build/workspace
でImageを作成して
docker run -p 8080:8080 -w /workspace --entrypoint /layers/org.cloudfoundry.openjdk/openjdk-jre/bin/java --rm docker-app-buildpacks:0.0.1-SNAPSHOT -Dspring.profiles.active=development org.springframework.boot.loader.JarLauncher
で起動できました。やったぜ!(空虚な喜び)
でもentrypointを上書きするとかダサい、ダサくない?ということでpack buildを使わずにDockerfileを使う場合は
FROM adoptopenjdk:11-jre-hotspot WORKDIR application COPY build/workspace ./ COPY start.sh ./ ENTRYPOINT ["./start.sh"]
#!/bin/sh exec java $@ org.springframework.boot.loader.JarLauncher
こんな感じ。というか結局Dockerfile書くならもっと良い方法たくさんありますよね。俺は何をやっているんだろう 😑
まとめ
Spring Boot 2.2でなんとかしてpack CLIを使ってみた、という記事でした。 無理やり感が凄いので、素直にSpring Boot 2.3のGAを待つことにします 🙃
おまけ
どうしてもpack CLIを使いたい場合、多分これが一番早いと思います。
./gradlew distZip pack build docker-app-buildpacks:0.0.1-SNAPSHOT --builder cloudfoundry/cnb:bionic --path ./build/distributions/docker-app-0.0.1-SNAPSHOT.zip docker run -p 8080:8080 --rm --entrypoint /layers/org.cloudfoundry.openjdk/openjdk-jre/bin/java docker-app-buildpacks:0.0.1-SNAPSHOT -jar /workspace/docker-app-0.0.1-SNAPSHOT/docker-app-web-0.0.1-SNAPSHOT.jar
参考
First look at Cloud Native Buildpacks support in Spring Boot 2.3 Milestone 1
Creating Docker images with Spring Boot 2.3.0.M1
An App's Brief Journey from Source to Image · Cloud Native Buildpack Documentation