Spring Bootを「動かす」単位を分解する ― 実行可能JARからコンテナまで
手元では動くJARを、そのままコンテナへコピーしたらイメージの再構築が毎回重い。原因を調べるには、JARとコンテナを一つの黒い箱として扱わず、何がどの頻度で変わるかへ分けて見る必要があります。
この回では、実行可能JAR、外部設定、コンテナレイヤー、ヘルス確認を「運ぶ単位」として整理します。Kubernetesの機能一覧やクラウドサービス比較は扱いません。
実行可能JARは何をまとめているか
./mvnw.cmd clean package
jar tf target/order-sample-0.0.1-SNAPSHOT.jar
Spring BootのJARでは、アプリのクラスがBOOT-INF/classes/、依存ライブラリがBOOT-INF/lib/に分かれます。MANIFEST.MFにはSpring Bootの起動ローダーと、実際のアプリケーション開始クラスに関する情報が入ります。
java -jar target/order-sample-0.0.1-SNAPSHOT.jar
この形なら、アプリケーションサーバーへWARを配置する手順を用意せず、JAR自身を実行単位として扱えます。
設定をJARへ焼き込みすぎない
DB接続先やログレベルなど、環境で変わる値は外から渡します。
$env:SPRING_PROFILES_ACTIVE='production'
$env:SPRING_DATASOURCE_URL='jdbc:postgresql://db.example/order'
java -jar target/order-sample-0.0.1-SNAPSHOT.jar
パスワードを記事やDockerfileへ直書きしません。本番環境ではSecret管理の仕組みを使います。
レイヤーへ分ける理由
アプリケーションコードは頻繁に変わりますが、Spring Frameworkなどの依存ライブラリは毎回変わるとは限りません。変化の頻度が違うものを同じコンテナレイヤーへ詰めると、小さなコード変更でも大きな依存層を作り直します。
Spring Bootのレイヤー構成では、概ね次の単位へ分けられます。
| レイヤー | 主な内容 | 変化の傾向 |
|---|---|---|
dependencies |
リリース版の依存ライブラリ | 比較的低頻度 |
spring-boot-loader |
Spring Bootの起動ローダー | Boot更新時 |
snapshot-dependencies |
SNAPSHOT依存(本サンプルは0件のため図では0 MB) | 開発中は変わりやすい |
application |
自作クラスとリソース | 通常の開発で高頻度 |
依存レイヤーを再利用できれば、アプリケーションコードだけを変更したときの転送量と再構築範囲を抑えられます。これは実行性能の話ではなく、主にビルドと配布の効率の話です。
BuildpacksでOCIイメージを作る
Spring Boot Maven Pluginを使う場合は、Dockerfileを自分で書かずにOCIイメージを作れます。
./mvnw.cmd spring-boot:build-image `
-Dspring-boot.build-image.imageName=example/order-sample:0.1.0
docker run --rm -p 8080:8080 `
-e SPRING_PROFILES_ACTIVE=container `
example/order-sample:0.1.0
containerプロファイルは例示であり、本サンプルに固有設定は含みません。
Buildpacksは便利ですが、ベースイメージ、JVM、SBOM、利用者、証明書などの運用条件を確認せずに採用するものではありません。組織のコンテナ基準がある場合は、それに合わせてDockerfile方式を選ぶこともあります。
Dockerfileで分ける場合の考え方
次はSpring Boot 3.5のtools jarmodeを使う最小例です。抽出後は各レイヤーを配置し、生成されたapplication.jarを実行します。
FROM eclipse-temurin:17-jre AS builder
WORKDIR /workspace
COPY target/order-sample-0.0.1-SNAPSHOT.jar application.jar
RUN java -Djarmode=tools -jar application.jar extract --layers --destination extracted
FROM eclipse-temurin:17-jre
WORKDIR /application
COPY --from=builder /workspace/extracted/dependencies/ ./
COPY --from=builder /workspace/extracted/spring-boot-loader/ ./
COPY --from=builder /workspace/extracted/snapshot-dependencies/ ./
COPY --from=builder /workspace/extracted/application/ ./
ENTRYPOINT ["java", "-jar", "application.jar"]
Spring Boot 3.5.16でextract --layersを実行し、dependencies、spring-boot-loader、snapshot-dependencies、applicationへ分かれることと、抽出後のapplication.jarを実行単位にすることを確認しました。今回の小さなサンプルでは、依存層が約58MB、application JARが約21KBでした。これは構成によって変わる測定例であり、一般的なサイズ保証ではありません。
起動したことと、使えることを分ける
プロセスが存在しても、DBへ接続できず注文APIが使えない場合があります。ActuatorのHealth情報を、コンテナのヘルスチェックやオーケストレーターのProbeへつなげます。
management.endpoint.health.probes.enabled=true
management.endpoints.web.exposure.include=health
curl.exe http://localhost:8080/actuator/health/liveness
curl.exe http://localhost:8080/actuator/health/readiness
- liveness:プロセスを再起動すべき状態か
- readiness:現在リクエストを受け付けてよいか
この二つを同じ意味として扱うと、外部サービスの一時障害でコンテナを再起動し続ける設計になり得ます。
上記設定(probes.enabled=true)でのSpring Boot 3.5.16のローカル起動では、/actuator/health、/actuator/health/liveness、/actuator/health/readinessがいずれもUPになることを確認しました。これはH2を使う単純なサンプルの結果です。本番では、どの依存先をreadinessへ含めるかを設計します。
デプロイ前の確認項目
- 使用したSpring Boot、Java、ベースイメージの版を記録したか
- JARとコンテナの両方で同じテストを通したか
- 設定とSecretをイメージから分離したか
- ヘルスチェックの意味と公開範囲を決めたか
- 依存ライブラリとベースイメージの脆弱性対応手順があるか
実務ではこうなる
コンテナ化しても、Javaの保守が消えるわけではありません。Spring Boot、JDK、OSパッケージ、ベースイメージを一組の配布物として追跡します。イメージのタグをlatestだけにせず、再現できる版とダイジェストを記録します。
BuildpacksとDockerfileのどちらを選んでも、非root実行、読み取り専用ファイルシステム、証明書、タイムゾーン、JVMメモリ、SBOM、脆弱性スキャンは別途確認します。コンテナのメモリ上限をJVMが認識していても、ヒープ以外の領域を含めた余白が必要です。
この作業環境ではDocker Engineを使ったイメージ実行までは行っていません。JARの起動、layer抽出、Health応答は実測済み、BuildpacksとDockerfileのコマンドはSpring Boot 3.5公式資料に基づくものとして区別しています。公開前・採用前には、実際のCIと配備基盤でイメージビルド、非root実行、Probe、再ビルド時のキャッシュを確認してください。
公式リファレンス
- Spring Boot 3.5: Packaging OCI Images
- Spring Boot 3.5: Efficient Container Images with Dockerfiles
- Spring Boot Maven Plugin: OCI Image
- Spring Boot 3.5: Kubernetes Probes
参考文献・参照資料
- Somnath Musib, Spring Boot in Practice, Manning, ISBN 9781617298813:第9章のJAR、レイヤー、コンテナを参照。
- Mark Heckler, Spring Boot:立ち上げて実行する、ISBN 9798341626911(AI翻訳版):実行可能JARの説明を補助参照。
書籍のコマンドやアプリ名は転載せず、架空の注文受付アプリへ置き換えています。Spring Boot 3.5で変わった抽出手順は、公式資料と3.5.16の実行結果で確認しました。
このシリーズでは、起動、DI、設定、HTTP、JPA、トランザクション、自動設定、テスト、配布を一つの注文受付サンプルでつなぎました。新しいアノテーションに出会ったときも、誰が起動時に読み、どのBeanやProxyを作り、どの境界へ処理を差し込むかへ戻ると、暗記から設計へ進めます。

