Skip to content

Week 7 - Multi-Stage Builds, Distroless, Minimal Images

7.1 Conceptual Core

  • The point of a build image is to not be the runtime image. A modern image pipeline:
  • Stage 1 (build): full build environment (compiler, headers, dev tools).
  • Stage 2 (test): the build artifacts plus test runners.
  • Stage 3 (runtime): a minimal image with just the artifact.
  • Distroless images (Google's gcr.io/distroless/*) contain only the runtime dependencies-no shell, no package manager, no cat. Smaller attack surface, smaller image, faster startup.
  • Static binaries (Go with CGO_ENABLED=0, Rust with musl, Java GraalVM native-image) can run on scratch (the empty base image): typically <20 MB total.

7.2 Mechanical Detail

  • Multi-stage Dockerfile:
    FROM golang:1.22-alpine AS build
    WORKDIR /src
    COPY . .
    RUN CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /app ./cmd/app
    
    FROM gcr.io/distroless/static:nonroot
    COPY --from=build /app /app
    USER nonroot:nonroot
    ENTRYPOINT ["/app"]
    
  • Distroless variants: static, base, cc, python3, java, etc. Pick the smallest that works.
  • The nonroot tag ensures the default user is UID 65532-never root.
  • The :debug tag adds busybox for emergency debugging-use only for one-off triage in dev.

7.3 Lab-"Three Image Diet"

Take a Go (or Rust, or Python) service and produce three images: 1. Naive: FROM ubuntu, build inline. Measure size. 2. Distroless: multi-stage with gcr.io/distroless/static. Measure size. 3. Scratch: static build, FROM scratch. Measure size.

Document the size delta and any operational tradeoffs (e.g., scratch has no ca-certificates -tls.Configfailures unless youCOPY --from=alpine /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/`).

7.4 Hardening Drill

  • Run docker scout cves (or trivy image) on each variant; observe that scratch and distroless have ~zero CVEs from the base, while ubuntu/alpine have many. The CVEs aren't gone-the attack surface is reduced. Internalize the difference.

7.5 Production Readiness Slice

  • Configure your CI to fail builds whose image grows by >5% vs the baseline. This forces conscious deltas; surprise growth is often a leaked dev tool.

Comments