# 1. The variants and how each is built [Index](../README.md) · Next: [2. Measuring size →](02-measuring-size.md) All nine start from the same `target/app.jar` (25 MB). The Dockerfiles are in [`docker/`](../docker), each with a comment saying what it is for. ## The layered pattern ```dockerfile FROM eclipse-temurin:25-jre AS builder WORKDIR /builder COPY target/app.jar application.jar RUN java -Djarmode=tools -jar application.jar extract --layers --destination extracted FROM gcr.io/distroless/java25-debian13:nonroot WORKDIR /application COPY --from=builder /builder/extracted/dependencies/ ./ COPY --from=builder /builder/extracted/spring-boot-loader/ ./ COPY --from=builder /builder/extracted/snapshot-dependencies/ ./ COPY --from=builder /builder/extracted/application/ ./ ENTRYPOINT ["java", "-jar", "application.jar"] ``` `extract` without `--launcher` writes a thin `application.jar` whose manifest `Class-Path` lists `lib/*.jar`, so the runtime stage launches with plain `java -jar` - no `JarLauncher`, no nested-jar class loading. `list-layers` on this jar prints `dependencies`, `spring-boot-loader`, `snapshot-dependencies`, `application`, in that order: least likely to change first. The builder stage uses the Temurin JRE, not the JDK: `extract` needs only a JVM. Only the jlink variant needs the JDK, for `jdeps` and `jlink`. ## Buildpacks and Jib in a restricted network The committed output was produced in a sandbox with no route to Docker Hub or Maven Central. The flags that made that work are in [`run-all.sh`](../scripts/run-all.sh): - Buildpacks: `-Pcorporate-proxy,no-maven-central -Dspring-boot.build-image.pullPolicy=IF_NOT_PRESENT` ([chapter 4](04-buildpacks.md)) - Jib: `-Djib.from.image=docker://eclipse-temurin:25-jre` - take the base image from the local daemon With ordinary internet access, `mvn spring-boot:build-image` and `mvn jib:dockerBuild` need no flags.