Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Java × distroless で 軽量なコンテナイメージを / Java on Dist...

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

Java × distroless で 軽量なコンテナイメージを / Java on Distroless

Avatar for Daisuke Garaike

Daisuke Garaike

May 29, 2026

More Decks by Daisuke Garaike

Other Decks in Programming

Transcript

  1. Daisuke Garaike • Product Engineer ◦ ハンディ株式会社 ◦ Backend ▪

    Kotlin, Java • サーバーサイド Kotlin, アジャイル, 自動テスト, プロダクト開発 3
  2. アジェンダ 1. Distroless を使う モチベーション 2. Java アプリを Distroless で

    動かす 3. コンテナイメージのサイズと 起動速度の比較 4. Java アプリを Distroless で 動かす際にやってほしいこと 4
  3. JVM のイメージは重い • docker イメージのサイズ ◦ amazoncorretto: 132.64 MB ◦

    eclipse-temurin: 143.42 MB ◦ 参考: ▪ debian: 47.03 MB • これらにアプリケーションが載る • 環境構築時に待たされる • 新規開発時に待たされる • Write Once, Run Anywhere と被っているから? 7
  4. 軽量イメージを使って問題解決 • debian-slim: 28.4 MB • Alpine Linux: 3.69 MB

    • Distroless: 10.99 MB ◦ Google 管理 ◦ シェルがないため攻撃に強い ◦ Java で Distroless を使っている話を あまり聞かないので今回のテーマに 8
  5. Distroless # syntax=docker/dockerfile:1 FROM gcr.io/distroless/java25-debian13:nonroot WORKDIR /deployments ARG JAR_FILE=build/libs/app.jar COPY

    --chown=nonroot:nonroot ${JAR_FILE} app.jar CMD ["app.jar"] 12 • JVM は Temurin • Entrypoint に `java -jar` が 指定されている
  6. Distroless x カスタム JRE # syntax=docker/dockerfile:1 FROM amazoncorretto:25.0.3-al2023 AS build

    WORKDIR /jlink RUN jlink \ --verbose \ --compress=2 \ --strip-java-debug-attributes \ --no-header-files \ --no-man-pages \ --add-modules [依存モジュール] \ --output jre-min 13 • アプリ実行に必要なモジュール のみを集めた JRE • Spring Boot アプリの 依存モジュールの調べ方は 割愛 FROM gcr.io/distroless/java-base-debian13:nonroot WORKDIR /deployments COPY --from=build --chown=nonroot:nonroot /jlink/jre-min /opt/jre-min ENV JAVA_HOME=/opt/jre-min ENV PATH=$JAVA_HOME/bin:$PATH ARG JAR_FILE=build/libs/app.jar COPY ${JAR_FILE} app.jar ENTRYPOINT ["java", "-jar", "app.jar"]
  7. Buildpacks x Distroless x カスタム JRE plugins { alias(libs.plugins.spring.boot) }

    tasks.bootBuildImage { runImage = "gcr.io/distroless/java-base-debian13:nonroot" imageName = "distroless-jvm-examples-distroless-custom-jre-buildpack" environment = mapOf( "BP_JVM_JLINK_ENABLED" to "true", "BP_JVM_JLINK_ARGS" to "--add-modules [依存モジュール]", ) } 14 [versions] spring-boot = "4.0.6" [plugins] spring-boot = { id = "org.springframework.boot", version.ref = "spring-boot" }
  8. サイズの比較 16 イメージ 圧縮後サイズ corretto 265.43 MB distroless 94.62 MB

    distroless-custom-jre 72.79 MB distroless-custom-jre-buildpack 87.92 MB
  9. コンテナ実行環境での起動時間の比較 • コンテナ起動時間とイメージサイズ ◦ pull 時間 + アプリ起動時間 = コンテナ起動時間

    • 実験手法 ◦ ECR + ECS Express ◦ デプロイ方式: カナリアデプロイ ▪ ベイク時間: 合計 6 分 ◦ 102 回再起動 17 引用: DevelopersIO, Classmethod, ECS Express Mode でデプロイにかかる時間を可能な限り短縮する, https://dev.classmethod.jp/articles/ecs-experss-reduce-deployment-time/
  10. コンテナ実行環境での起動時間の比較 • 結果 18 秒 corretto Distroless Buildpacks x Distroless

    x カスタム JRE Distroless x カスタム JRE • Dockerfile 形式同士: 軽量なほど起動時間が速い • サイズだけが起動時間に影響している訳ではない
  11. ローカルから docker で起動しておく • ローカルでもクラウドでも同じものを実行する ◦ The Twelve Factor App

    • compose.yaml ◦ アプリ起動に必要な環境変数もまとめられる • 起動方法 ◦ Jar ファイルのビルド: gradle build ◦ コンテナ実行: docker compose up --build 20
  12. コンテナレベルのブラックボックステスト • アプリの異常だけでなく コンテナの異常を検知できる • プラグインで自動化 ◦ テスト実行前: compose up

    ◦ テスト実行後: compose down 21 [versions] docker-compose = "0.17.21" [plugins] docker-compose = { id = "com.avast.gradle.docker-compose", version.ref = "docker-compose" } plugins { alias(libs.plugins.docker.compose) } dockerCompose { useComposeFiles = listOf("../compose.yaml") } tasks.test { useJUnitPlatform() mustRunAfter("composeUp") } tasks.composeDown { mustRunAfter("test") } tasks.register("integrationTest") { dependsOn("composeUp") dependsOn("test") dependsOn("composeDown") }
  13. リモートデバッグ • ローカルでコンテナを実行してもデバッグが可能 • JRE に jdk.jdwp.agent を追加 • 5005

    ポートの解放 • 環境変数 JAVA_TOOL_OPTIONS 22 services: distroless-custom-jre: build: context: ./app dockerfile: Dockerfile_distroless_custom_jre ports: - "8083:8080" - "5005:5005" environment: JAVA_TOOL_OPTIONS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005
  14. docker compose のヘルスチェックが難しい • Dockerfile や compose.yaml のヘルスチェックは コンテナ内でコマンドを実行する •

    curl がないためヘルスチェックができない • クラウドの場合は問題ないことが多いので 気にしていない 23
  15. まとめ • イメージサイズの軽量化は、これらの時間短縮につながる ◦ ローカル環境での初回 pull ◦ コンテナレジストリへの初回 push ◦

    コンテナ実行環境での起動時間 • コンテナ起動時間の短縮は、 サイズだけではなくコンテナ構造も影響する • コンテナイメージを工夫する場合、 常にコンテナでアプリを起動するようにする 25