Choosing a base image

Docker · lesson 6 of 31 · 4 min read

Choose between JDK and JRE, and between Debian, Alpine and distroless, without guessing.

Open this lesson in the learning hub

Key points

  • Build with a JDK, run on a JRE. Shipping javac to production adds size and attack surface for nothing.
  • eclipse-temurin:21-jre is 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. :latest means your build is not reproducible tomorrow.
  • No JRE published for your version? Build a trimmed runtime with jlink and 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.