Docker Multi Stage Builds
Docker Multi-Stage Builds: Optimierte Images
Multi-Stage Builds reduzieren Image-Größen drastisch. Trennen Sie Build-Tools von der Runtime für sichere, schlanke Container.
Das Problem
# Ohne Multi-Stage: Alles im finalen Image FROM node:20 WORKDIR /app COPY package*.json ./ RUN npm install # Dev Dependencies! COPY . . RUN npm run build # Build Tools bleiben! CMD ["node", "dist/app.js"] # Image-Größe: ~1 GB # Enthält: TypeScript, Webpack, alle devDependencies...
Die Lösung: Multi-Stage
# Stage 1: Build FROM node:20 AS builder WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build # Stage 2: Production FROM node:20-alpine WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY --from=builder /app/dist ./dist USER node CMD ["node", "dist/app.js"] # Image-Größe: ~150 MB # Enthält: Nur Production Dependencies und Build-Output
Vergleich
| Aspekt | Single-Stage | Multi-Stage |
|---|---|---|
| Image-Größe | ~1 GB | ~150 MB |
| Attack Surface | Groß | Minimal |
| Build-Tools | Im Image | Nicht im Image |
| Secrets-Risiko | Höher | Niedriger |
Go Beispiel
# Build Stage FROM golang:1.21 AS builder WORKDIR /app COPY go.mod go.sum ./ RUN go mod download COPY . . RUN CGO_ENABLED=0 GOOS=linux go build -o main . # Final Stage: Scratch (leer!) FROM scratch COPY --from=builder /app/main /main COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ ENTRYPOINT ["/main"] # Image-Größe: ~10 MB (nur Binary!)
Python Beispiel
# Build Stage FROM python:3.11 AS builder WORKDIR /app RUN pip install poetry COPY pyproject.toml poetry.lock ./ RUN poetry export -f requirements.txt > requirements.txt RUN pip wheel --no-cache-dir --no-deps --wheel-dir /wheels -r requirements.txt # Final Stage FROM python:3.11-slim WORKDIR /app COPY --from=builder /wheels /wheels RUN pip install --no-cache /wheels/* COPY . . USER nobody CMD ["python", "main.py"]
React/Vue Frontend
# Build Stage FROM node:20 AS builder WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build # Production Stage: Nginx FROM nginx:alpine COPY --from=builder /app/dist /usr/share/nginx/html COPY nginx.conf /etc/nginx/conf.d/default.conf EXPOSE 80 CMD ["nginx", "-g", "daemon off;"] # Image-Größe: ~25 MB
Mehrere Build-Stages
# Stage 1: Dependencies FROM node:20 AS deps WORKDIR /app COPY package*.json ./ RUN npm ci # Stage 2: Build FROM node:20 AS builder WORKDIR /app COPY --from=deps /app/node_modules ./node_modules COPY . . RUN npm run build RUN npm run test # Stage 3: Production Dependencies FROM node:20 AS prod-deps WORKDIR /app COPY package*.json ./ RUN npm ci --only=production # Stage 4: Final FROM node:20-alpine WORKDIR /app COPY --from=prod-deps /app/node_modules ./node_modules COPY --from=builder /app/dist ./dist USER node CMD ["node", "dist/app.js"]
Selektiv kopieren
# Nur bestimmte Dateien aus Stage kopieren COPY --from=builder /app/dist ./dist COPY --from=builder /app/package.json ./ # Von externem Image kopieren COPY --from=nginx:alpine /etc/nginx/nginx.conf /etc/nginx/ # Von anderem Named Stage FROM builder AS tester RUN npm run test FROM builder AS final # ...
Build-Argumente nutzen
ARG NODE_ENV=production
FROM node:20 AS builder
ARG NODE_ENV
WORKDIR /app
COPY . .
RUN npm ci
RUN npm run build -- --mode ${NODE_ENV}
FROM node:20-alpine
COPY --from=builder /app/dist ./dist
CMD ["node", "dist/app.js"]
# Build mit Argument docker build --build-arg NODE_ENV=staging -t myapp:staging .
Caching optimieren
# ✅ Gut: Dependencies zuerst (cached wenn unverändert) COPY package*.json ./ RUN npm ci COPY . . RUN npm run build # ❌ Schlecht: Alles zusammen (kein Cache) COPY . . RUN npm ci && npm run build
Debug-Stage
FROM node:20 AS builder # ... build steps FROM node:20-alpine AS production # ... production setup FROM node:20 AS development WORKDIR /app COPY --from=builder /app/node_modules ./node_modules COPY . . CMD ["npm", "run", "dev"]
# Bestimmte Stage bauen docker build --target development -t myapp:dev . docker build --target production -t myapp:prod .
💡 Tipp:
Nutzen Sie Multi-Stage Builds immer für Production-Images. Die kleineren Images starten schneller und sind sicherer.