Skip to content
BotServBotServ
DockerImageOptimierungMulti-StageLayer

Docker-Images optimieren

Docker-Images kleiner und schneller machen. Layer-Optimierung, Multi-Stage, .dockerignore und Best Practices.

S

schutzgeist

3 min read
Docker-Images optimieren

Docker-Images optimieren

Was dieser Artikel über Docker-Image-Optimierung behandelt

  • Warum kleine Images sinnvoll sind.
  • Wie Layer und Caching funktionieren.
  • Multi-Stage-Builds und .dockerignore.
  • Basis-Image-Auswahl.
  • Sicherheits- und Performance-Best-Practices.

Einleitung: Docker-Images optimieren

Grosse Docker-Images verlangsamen Builds, Deployments und Downloads. Sie erhöhen die Angriffsfläche, weil mehr Software installiert ist, und belegen unnötig Speicher. Durch gezielte Optimierung lassen sich Images oft von mehreren Gigabyte auf einige hundert Megabyte reduzieren, ohne Funktionalität zu verlieren.

Dieser Artikel zeigt, wie man Docker-Images klein, schnell und sicher macht.

Wichtige Begriffe

  • Layer: Schicht in einem Docker-Image.
  • Caching: Wiederverwendung unveränderter Layer.
  • Multi-Stage-Build: Mehrere Bauabschnitte in einem Dockerfile.
  • .dockerignore: Datei, die unerwünschte Dateien vom Build ausschliesst.
  • Base Image: Grundlage des Images.
  • Distroless: Image ohne Shell und unnötige Tools.
  • Squashing: Zusammenfassen mehrerer Layer.

Warum Images optimieren?

  • Schnellere Builds und Deployments.
  • Weniger Speicherbedarf.
  • Kleinere Angriffsfläche.
  • Weniger Bandbreite beim Verteilen.
  • Einfachere Wartung und Prüfung.

Basis-Image wählen

Gross vs. klein

BasisGrösseVorteilNachteil
ubuntu~78 MBViele ToolsRelativ gross
debian:slim~30 MBAusgewogenWeniger Tools
alpine~5 MBSehr kleinmusl-Kompatibilität
distrolessunter 5 MBMinimalKein Shell, schwerer Debugging

Empfehlung

  • Für Python: python:3.11-slim.
  • Für Node.js: node:20-alpine oder slim.
  • Für Go: golang:alpine oder scratch für fertige Binaries.
  • Für kritische Umgebungen: distroless.

Multi-Stage-Builds

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

# Runtime
FROM node:20-slim
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["node", "dist/index.js"]

Nur die Laufzeitdateien landen im finalen Image.

Layer und Caching optimieren

Jede Anweisung im Dockerfile erzeugt einen Layer. Häufig geänderte Befehle sollten am Ende stehen:

# Abhängigkeiten zuerst, ändern sich selten
COPY package*.json ./
RUN npm ci

# Quellcode zuletzt, ändert sich oft
COPY . .

So wird das Layer-Caching effektiv genutzt.

.dockerignore

Verhindert, dass unnötige Dateien ins Build-Context gelangen:

node_modules
.git
*.log
.env
Dockerfile
.dockerignore
README.md
tests/

Befehle zusammenfassen

Statt:

RUN apt-get update
RUN apt-get install -y curl
RUN apt-get clean

besser:

RUN apt-get update && apt-get install -y curl && apt-get clean && rm -rf /var/lib/apt/lists/*

Das erzeugt einen einzigen Layer und entfernt Caches.

Nicht benötigte Tools entfernen

  • Build-Tools wie Compiler nur in Builder-Stages.
  • apt-get clean und Listen entfernen.
  • npm ci statt npm install.
  • Keine Dokumentation oder Beispiele im Image.
  • Keine Testverzeichnisse im Produktions-Image.

Non-Root-User

FROM node:20-slim
RUN useradd -m appuser
USER appuser

Das reduziert das Risiko bei Container-Breakouts.

Labels und Metadaten

LABEL maintainer="team@example.com"
LABEL org.opencontainers.image.source="https://github.com/user/repo"
LABEL org.opencontainers.image.version="1.0.0"

Healthchecks einbauen

HEALTHCHECK --interval=30s --timeout=3s \
  CMD curl -f http://localhost:3000/health || exit 1

Image analysieren

Tools zur Analyse:

docker history mein-image:latest
dive mein-image:latest

dive zeigt, welche Layer viel Speicher belegen.

Beispiel: Optimiertes Dockerfile

# Builder
FROM python:3.11-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir --user -r requirements.txt

# Runtime
FROM python:3.11-slim
WORKDIR /app
RUN useradd -m appuser
COPY --from=builder /root/.local /home/appuser/.local
COPY --chown=appuser:appuser . .
USER appuser
ENV PATH=/home/appuser/.local/bin:$PATH
HEALTHCHECK CMD curl -f http://localhost:8000/health || exit 1
CMD ["python", "main.py"]

Sicherheit

  • Regelmässig neue Basis-Images nutzen.
  • Images auf Schwachstellen scannen.
  • Keine Secrets im Image.
  • Minimale Packages installieren.
  • Read-only Filesystem erwägen.
  • latest vermeiden.

Typische Stolpersteine

  • COPY . . zu früh: Invalidiert Cache bei jeder Codeänderung.
  • Keine .dockerignore: Build-Kontext wird riesig.
  • Build-Tools im finalen Image: Grösser und unsicherer.
  • Als root laufen: Erhöhtes Risiko.
  • Zu viele Layer: Jeder RUN erzeugt einen.
  • Grosse Basis-Images: Unnötig, wenn slim reicht.
  • Kein apt clean: Layer wird unnötig gross.

FAQ: Docker-Images optimieren

Wie klein sollte ein Image sein? So klein wie möglich, ohne Funktion zu verlieren. Oft unter 100 MB für einfache Apps.

Ist Alpine immer besser? Nicht immer. musl kann bei manchen Libraries zu Problemen führen.

Brauche ich Multi-Stage? Bei kompilierten Sprachen und Node.js meist ja.

Was ist distroless? Ein extrem minimales Image ohne Shell, nur Laufzeitdateien.

Wie prüfe ich die Imagegrösse? Mit docker images, docker history oder dive.

Quellen und weiterführende Literatur

Zusammenfassung: Docker-Images optimieren

Optimierte Docker-Images sind kleiner, schneller und sicherer. Wichtige Massnahmen sind die Wahl eines schlanken Basis-Images, Multi-Stage-Builds, Layer-Caching, eine gute .dockerignore und das Entfernen unnötiger Tools. Non-Root-User, Healthchecks und Labels runden das Image ab. Wer regelmässig Images scannt und mit dive analysiert, behält die Kontrolle über Grösse und Sicherheit.

Zurück zum KI Blog
Share:

Ähnliche Beiträge