build smaller java runtime with sbt-native-packager & docker-plugin
Pre-requisites
- sbt with sbt-native-packager plugin enabled
Background
JDK Version 11+ 以降、JREの提供がデフォルトでされなくなっていることを背景に、 どうやって小さなコンテナイメージを作るかを調べて行き着いた方法。
jlink
という仕組みの提供はあるものの、比較的設定項目が多く、
build設定の定期的なメンテナンスコストがかかりそうな印象があったため、
何も考えずJDK入りのイメージを使うのに比べて軽量で、 メンテナンスもさほどかからないだろうやり方のメモ。
Quick Summary
仮に、akka-http
で作られたScalaアプリケーションがあるとして、
sbt-native-packager
を使ってimageをbuildしたいとすると、以下が build.sbt
で設定する方法の例。
lazy val api = Project("app", file("api"))
.enablePlugins(JavaAppPackaging, AshScriptPlugin, DockerPlugin)
.settings(
version:= "latest",
dockerCommands:= Seq(
Cmd("FROM", "amazoncorretto:11-alpine as stage"),
Cmd("RUN", "rm -rf /usr/lib/jvm/java-11-amazon-corretto/jmods && rm -rf /usr/lib/jvm/java-11-amazon-corretto/lib/src.zip"),
Cmd("FROM", "alpine:3.16.0 as main"),
Cmd("WORKDIR", "/opt/docker"),
Cmd("COPY", "1/opt/docker ."),
Cmd("COPY", "2/opt/docker ."),
Cmd("COPY", "--from=stage /usr/lib/jvm /usr/lib/jvm"),
Cmd("ENV", "LANG C.UTF-8"),
Cmd("ENV", "JAVA_HOME /usr/lib/jvm/default-jvm"),
Cmd("ENV", "PATH $JAVA_HOME/bin:$PATH"),
ExecCmd("ENTRYPOINT", s"/opt/docker/bin/${name.value}")
)
)
.settings(
libraryDependencies ++= Seq(
"com.typesafe.akka" %% "akka-http" % "10.1.12",
"de.heikoseeberger" %% "akka-http-circe" % "1.33.0"
)
)
- DockerのMultiStageBuildを利用する
- stageフェーズではベースイメージとしてamazon-correttoを利用する
- ベースイメージからruntimeとしてはいらないファイルを削除する(これだけで
120MB
近く削れる) - mainステージでアプリケーション本体を
sbt-native-packager
のdocker:stage
の構造に合わせてコピー - stageフェーズでダイエットしたjvmを移植する
sbt-native-packager
のアプリのパッケージングとしてのガワの部分を整えてimageを生成
Notes
jlink
で一番面倒に思った部分は、--add-modules オプション。これがよしなにやってくれれば一番嬉しかったが、
一工夫必要にみえて、そこまではやらなくてもいいかなと尻込みしてしまった。
イメージのサイズを追求してしまうと、もう言語を変える方が賢明となりがちなので、 簡単に実現できるかどうかはやっぱり重要。
© Shuhei Kimura.RSS