Choosing a base image
Choose between JDK and JRE, and between Debian, Alpine and distroless, without guessing.
Open this lesson in the learning hubKey points
- Build with a JDK, run on a JRE. Shipping
javacto production adds size and attack surface for nothing. eclipse-temurin:21-jreis the safe default: glibc, familiar Ubuntu tooling, broad architecture coverage.- Alpine uses musl libc instead of glibc. Very small, but it can surprise native libraries and JNI code.
- Distroless images ship no shell and no package manager. Tiny and hard to attack, also hard to debug.
- Pin a real tag or a digest.
:latestmeans your build is not reproducible tomorrow. - No JRE published for your version? Build a trimmed runtime with
jlinkand copy it into a bare base.
Example
# roomy, glibc, easy to debug - the sensible default
FROM eclipse-temurin:21-jre
# smaller, musl libc, fewer architectures published
FROM eclipse-temurin:21-jre-alpine
# smallest realistic runtime: no shell, no apt, runs as nonroot
FROM gcr.io/distroless/java21-debian12:nonroot
# fully pinned by digest - byte-identical rebuilds
FROM eclipse-temurin:21-jre@sha256:0a1b2c3d...
JRE at runtime, pinned tag always, distroless only once you know how you will debug it.
This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Docker course, and every lesson in it is listed on the Docker contents page.