Add docker-images: one Spring Boot 4 service packaged nine ways
Companion code for "Dockerizing Spring Boot 4: Layered Jars, Buildpacks, Distroless and Image Size Benchmarks". Fat jar on JDK and JRE, layered jar on Debian, Alpine and distroless, jlink, the JDK 25 AOT cache, Paketo buildpacks and Jib, each measured for size on disk and pushed, rebuild delta, startup, user and shell. Also PID 1 and signal handling, the jdeps module gap, AOT cache mismatches and buildpacks memory calculation. Transcripts in docs/output/, regenerated by scripts/run-all.sh. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01C3TETMrqVUWeFkNtz3Jbo3
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
## sbd/docker-images:aot-cache
|
||||
Starting ImagesApplication v1.0.0 using Java 25.0.4 with PID 1 (/application/application.jar started by root in /applica
|
||||
Started ImagesApplication in 1.657 seconds (process running for 1.966)
|
||||
exit status while running: running
|
||||
|
||||
## sbd/docker-images:aot-cache-mismatch
|
||||
[0.007s][warning][aot] The AOT cache was created by a different version or build of HotSpot
|
||||
[0.007s][error ][aot] An error has occurred while processing the AOT cache. Run with -Xlog:aot for details.
|
||||
[0.008s][error ][aot] Loading static archive failed.
|
||||
[0.008s][error ][aot] Unable to map shared spaces
|
||||
Starting ImagesApplication v1.0.0 using Java 25.0.4.1 with PID 1 (/application/application.jar started by nonroot in /ap
|
||||
Started ImagesApplication in 3.564 seconds (process running for 4.05)
|
||||
exit status while running: running
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
# docker history sbd/docker-images:buildpacks
|
||||
69B Buildpacks Process Types
|
||||
1.94kB Buildpacks Launcher Config
|
||||
2.93MB Buildpacks Application Launcher
|
||||
0B Application Slice: 5
|
||||
14.2kB Application Slice: 4
|
||||
0B Application Slice: 3
|
||||
402kB Application Slice: 2
|
||||
25.9MB Application Slice: 1
|
||||
577kB Software Bill-of-Materials
|
||||
3B Layer: 'web-application-type', Created by buildpack: paketo-buildpacks/[email protected]
|
||||
77.4kB Layer: 'spring-cloud-bindings', Created by buildpack: paketo-buildpacks/[email protected]
|
||||
4.01MB Layer: 'helper', Created by buildpack: paketo-buildpacks/[email protected]
|
||||
11B Layer: 'classpath', Created by buildpack: paketo-buildpacks/[email protected]
|
||||
276MB Layer: 'jre', Created by buildpack: paketo-buildpacks/[email protected]
|
||||
214B Layer: 'java-security-properties', Created by buildpack: paketo-buildpacks/[email protected]
|
||||
5.48MB Layer: 'helper', Created by buildpack: paketo-buildpacks/[email protected]
|
||||
5.18MB Layer: 'helper', Created by buildpack: paketo-buildpacks/[email protected]
|
||||
519B
|
||||
191B
|
||||
24.9MB
|
||||
@@ -0,0 +1,16 @@
|
||||
## docker run -m 512m
|
||||
unable to calculate memory configuration
|
||||
fixed memory regions require 595872K which is greater than 512M available for allocation: -XX:MaxDirectMemorySize=10M, -XX:MaxMetaspaceSize=83872K, -XX:ReservedCodeCacheSize=240M, -Xss1M * 250 threads
|
||||
ERROR: failed to launch: exec.d: failed to execute exec.d file at path '/layers/paketo-buildpacks_bellsoft-liberica/helper/exec.d/memory-calculator': exit status 1
|
||||
state: exited (exit 82)
|
||||
|
||||
## docker run -m 768m
|
||||
Calculated JVM Memory Configuration: -XX:MaxDirectMemorySize=10M -Xmx190559K -XX:MaxMetaspaceSize=83872K -XX:ReservedCodeCacheSize=240M -Xss1M (Total Memory: 768M, Thread Count: 250, Loaded Class Count: 12394, Headroom: 0%)
|
||||
Started ImagesApplication in 3.884 seconds (process running for 4.423)
|
||||
state: running (exit 0)
|
||||
|
||||
## docker run -m 512m -e BPL_JVM_THREAD_COUNT=50
|
||||
Calculated JVM Memory Configuration: -XX:MaxDirectMemorySize=10M -Xmx133215K -XX:MaxMetaspaceSize=83872K -XX:ReservedCodeCacheSize=240M -Xss1M (Total Memory: 512M, Thread Count: 50, Loaded Class Count: 12394, Headroom: 0%)
|
||||
Started ImagesApplication in 3.846 seconds (process running for 4.353)
|
||||
state: running (exit 0)
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# Spring Boot 4.1.1 application (webmvc + actuator + validation + prometheus), fat jar 25M
|
||||
# Docker Engine 29.4.3, classic overlay2 store. 3 startup runs each, median shown.
|
||||
# 'on disk' = docker image inspect .Size (uncompressed). 'pushed' = layer blobs + config in the registry (compressed).
|
||||
|
||||
variant on disk pushed layers user shell packages ready ms Started RSS JVM
|
||||
fatjar-jdk 456M 178M 7 root yes 115 (dpkg) 5362 3.932s 169.5MiB Eclipse 25.0.4
|
||||
fatjar-jre 377M 144M 7 root yes 106 (dpkg) 5091 3.944s 182.1MiB Eclipse 25.0.4
|
||||
layered-jre 377M 144M 11 root yes 106 (dpkg) 4272 3.356s 169.5MiB Eclipse 25.0.4
|
||||
layered-alpine 251M 98M 10 root yes 44 (apk) 4634 3.775s 145.9MiB Eclipse 25.0.4
|
||||
layered-distroless 252M 97M 39 65532 no 25 (status.d) 4118 3.254s 164.3MiB Eclipse 25.0.4.1
|
||||
jlink-distroless 119M 76M 39 65532 no 24 (status.d) 4386 3.39s 165.7MiB Eclipse 25.0.4
|
||||
aot-cache 440M 160M 12 root yes 106 (dpkg) 2412 1.638s 174.6MiB Eclipse 25.0.4
|
||||
buildpacks 345M 125M 20 1002:1001 no 10 (status.d) 4726 3.615s 183.6MiB BellSoft 25.0.4
|
||||
jib 377M 144M 10 root yes 106 (dpkg) 4323 3.457s 162.5MiB Eclipse 25.0.4
|
||||
@@ -0,0 +1,31 @@
|
||||
# The same eleven images, loaded from the same tarballs, listed by `docker images` under the two
|
||||
# Docker Engine 29.4.3 image stores. Captured once by hand (switching stores needs a daemon
|
||||
# restart); the commands are in docs/02-measuring-size.md.
|
||||
|
||||
## containerd image store (daemon.json: {"features":{"containerd-snapshotter":true}} - the default for new installs)
|
||||
REPOSITORY:TAG IMAGE ID SIZE
|
||||
paketobuildpacks/ubuntu-noble-run-tiny:latest 5fb8a81f3f56 38.7MB
|
||||
eclipse-temurin:25-jre 211325bca3fd 496MB
|
||||
eclipse-temurin:25-jdk 00eacca34899 608MB
|
||||
eclipse-temurin:25-jre-alpine 31a7faf76302 305MB
|
||||
bellsoft/liberica-openjre-debian:25-cds 78b8d1ba9172 505MB
|
||||
quay.io/prometheus/prometheus:v3.14.0 0230c2ba4c1c 372MB
|
||||
busybox:1.37 e0b4f7eca906 6.77MB
|
||||
registry.k8s.io/prometheus-adapter/prometheus-adapter:v0.12.0 b8e2bc8f8de9 131MB
|
||||
paketobuildpacks/builder-noble-java-tiny:latest b54d7bce7d3c 1.26GB
|
||||
gcr.io/distroless/java-base-debian13:nonroot fe682f609c79 43.1MB
|
||||
gcr.io/distroless/java25-debian13:nonroot 3ad8b3cc79ab 305MB
|
||||
|
||||
## classic overlay2 store (daemon.json: {"features":{"containerd-snapshotter":false}})
|
||||
REPOSITORY:TAG IMAGE ID SIZE
|
||||
paketobuildpacks/ubuntu-noble-run-tiny:latest 3f2697c8829c 24.9MB
|
||||
eclipse-temurin:25-jre a33388e97452 352MB
|
||||
eclipse-temurin:25-jdk ca0436742d32 430MB
|
||||
eclipse-temurin:25-jre-alpine 0988c057a1e4 226MB
|
||||
bellsoft/liberica-openjre-debian:25-cds aea7393405da 356MB
|
||||
quay.io/prometheus/prometheus:v3.14.0 31c1e0aacb3a 261MB
|
||||
busybox:1.37 db287cb6be81 4.42MB
|
||||
registry.k8s.io/prometheus-adapter/prometheus-adapter:v0.12.0 3bba96c2e4e6 89.3MB
|
||||
paketobuildpacks/builder-noble-java-tiny:latest d835ec7c8f6e 868MB
|
||||
gcr.io/distroless/java-base-debian13:nonroot 9bc10980a41f 26.5MB
|
||||
gcr.io/distroless/java25-debian13:nonroot be8c5fbd580c 226MB
|
||||
@@ -0,0 +1,30 @@
|
||||
# jlink modules chosen by jdeps alone:
|
||||
java.base java.compiler java.datatransfer java.desktop java.instrument java.logging java.management java.naming java.net.http java.prefs java.scripting java.security.jgss java.security.sasl java.sql java.transaction.xa java.xml jdk.jfr jdk.unsupported
|
||||
|
||||
# WARN lines at startup of the jdeps-only image:
|
||||
i.m.c.i.binder.jvm.JvmGcMetrics : GC notifications will not be available because com.sun.management.GarbageCollectionNotificationInfo is not present
|
||||
i.m.c.i.binder.jvm.JvmGcMetrics : GC notifications will not be available because no GarbageCollectorMXBean of the JVM provides any. GCs=[G1 Young Generation, G1 Concurrent GC, G1 Old Generation]
|
||||
|
||||
# Metric names: full JRE 61, jdeps-only 46, jdeps + jdk.management 58
|
||||
# Present with the full JRE, missing from the jdeps-only image:
|
||||
jvm_gc_concurrent_phase_time_seconds_count
|
||||
jvm_gc_concurrent_phase_time_seconds_max
|
||||
jvm_gc_concurrent_phase_time_seconds_sum
|
||||
jvm_gc_live_data_size_bytes
|
||||
jvm_gc_max_data_size_bytes
|
||||
jvm_gc_memory_allocated_bytes_total
|
||||
jvm_gc_memory_promoted_bytes_total
|
||||
jvm_gc_pause_seconds_count
|
||||
jvm_gc_pause_seconds_max
|
||||
jvm_gc_pause_seconds_sum
|
||||
process_cpu_time_ns_total
|
||||
process_cpu_usage
|
||||
process_files_max_files
|
||||
process_files_open_files
|
||||
system_cpu_usage
|
||||
# Missing from jdeps + jdk.management: 3
|
||||
jvm_gc_concurrent_phase_time_seconds_count
|
||||
jvm_gc_concurrent_phase_time_seconds_max
|
||||
jvm_gc_concurrent_phase_time_seconds_sum
|
||||
# (jvm_gc_concurrent_phase_time_* is registered lazily, after the first G1 concurrent cycle -
|
||||
# whether it appears within a few seconds of startup varies run to run, in either image.)
|
||||
@@ -0,0 +1,12 @@
|
||||
# docker stop sends SIGTERM to PID 1, waits 10 s, then SIGKILL. Exit code 143 = the JVM handled
|
||||
# SIGTERM (128+15). 137 = it was killed (128+9).
|
||||
|
||||
layered-jre PID 1: java -jar application.jar docker stop: 244 ms exit code: 143 graceful-shutdown log lines: 1
|
||||
shell-form PID 1: /bin/sh -c java -jar /app/app.jar docker stop: 10160 ms exit code: 137 graceful-shutdown log lines: 0
|
||||
shell-form-alpine PID 1: java -jar /app/app.jar docker stop: 219 ms exit code: 143 graceful-shutdown log lines: 1
|
||||
shell-form-wrapper PID 1: /bin/sh -c echo "starting revision $(date +%s)" && java -j docker stop: 10176 ms exit code: 137 graceful-shutdown log lines: 0
|
||||
layered-distroless PID 1: (image has no cat; ENTRYPOINT is exec form) docker stop: 256 ms exit code: 143 graceful-shutdown log lines: 1
|
||||
|
||||
# What /bin/sh is in each base image:
|
||||
eclipse-temurin:25-jre -> /usr/bin/dash
|
||||
eclipse-temurin:25-jre-alpine -> /bin/busybox
|
||||
@@ -0,0 +1,14 @@
|
||||
# One-line code change (BuildInfo.REVISION 1 -> 2), every variant rebuilt.
|
||||
# 'new layers' = layer digests in revision 2 that revision 1 did not have: what a push uploads
|
||||
# and what a node that already runs revision 1 downloads.
|
||||
|
||||
variant new layers bytes to push image total share
|
||||
fatjar-jdk 1 of 7 23422K 178M 13.1%
|
||||
fatjar-jre 1 of 7 23422K 144M 16.2%
|
||||
layered-jre 1 of 11 6K 144M 0.0%
|
||||
layered-alpine 1 of 10 6K 98M 0.0%
|
||||
layered-distroless 1 of 39 6K 97M 0.0%
|
||||
jlink-distroless 1 of 39 6K 76M 0.0%
|
||||
aot-cache 2 of 12 15323K 160M 9.6%
|
||||
buildpacks 2 of 20 64K 125M 0.1%
|
||||
jib 1 of 10 2K 144M 0.0%
|
||||
Reference in New Issue
Block a user