Multi-Stage Builds - Docker-Images drastisch verkleinern

Multi-Stage Builds - Docker-Images drastisch verkleinern

Build-Tools, Compiler und Testframeworks braucht man zum Bauen einer Anwendung — aber nicht zum Ausführen. Multi-Stage Builds trennen beides sauber voneinander.

Das Problem: aufgeblähte Images

Ein naiver Ansatz packt alles in ein Image:

FROM golang:1.21
WORKDIR /app
COPY . .
RUN go build -o server .
CMD ["./server"]

Resultat: Das Image enthält die gesamte Go-Toolchain (~800 MB), obwohl zur Laufzeit nur das fertige Binary gebraucht wird.

Die Lösung: mehrere FROM-Stages

Multi-Stage Builds erlauben mehrere FROM-Instruktionen in einem Dockerfile. Jede Stage ist eine eigene Build-Umgebung. Mit COPY --from= werden nur die nötigen Artefakte in die nächste Stage übernommen.

# Stage 1: Build-Umgebung
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o server .

# Stage 2: Laufzeit-Image
FROM alpine:3.18
WORKDIR /app
COPY --from=builder /app/server .
EXPOSE 8080
CMD ["./server"]

Resultat: Das finale Image enthält nur Alpine (~7 MB) + das Binary. Statt 800 MB sind es nun ~12 MB.

Beispiel mit Node.js

FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:20-alpine AS runtime
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY --from=builder /app/dist ./dist
EXPOSE 3000
CMD ["node", "dist/index.js"]

node_modules aus dem Builder enthält dev-Dependencies (TypeScript, ESLint usw.) — die kommen nicht ins Runtime-Image.

Einzelne Stages bauen

Man kann gezielt eine bestimmte Stage bauen, z. B. nur den Builder zum Debuggen:

docker build --target builder -t myapp-debug .

Vorteile zusammengefasst

  • Kleinere Images → schnellere Deploys, weniger Angriffsfläche
  • Build-Tools landen nie in Produktion
  • Kein Aufräumen von Caches und temporären Dateien nötig — die Build-Stage wird schlicht verworfen
  • Alles in einem Dockerfile — kein separates Build-Skript

Multi-Stage Builds sind heute Standard für jede Sprache mit Compile-Schritt.