Dockerfile Best Practices - was wirklich zählt

Dockerfile Best Practices - was wirklich zählt

Es gibt viele Ratschläge für Dockerfiles — dieser Artikel fokussiert auf die Punkte, die in der Praxis tatsächlich einen Unterschied machen.

1. Spezifische Basis-Image-Tags pinnen

# Schlecht
FROM node:latest

# Gut
FROM node:20.11.0-slim

latest ist kein Version — bei einem docker pull kann Breaking Change kommen. Exakte Tags machen Builds reproduzierbar.

2. Einen Prozess pro Container

Container sollten genau einen Hauptprozess haben. Nicht nginx + PHP-FPM + cron in einen Container — das ist das Konzept klassischer VMs, nicht Container.

Mehrere Dienste: Docker Compose oder Kubernetes, jeder Dienst sein eigener Container.

3. Non-Root-User verwenden

Standardmäßig laufen Container als root. Das ist ein unnötiges Risiko.

FROM node:20-slim
WORKDIR /app
COPY --chown=node:node . .
RUN npm ci --omit=dev
USER node
CMD ["node", "index.js"]

Bei Debian-basierten Images ist node-User bereits vorhanden. Alternativ:

RUN groupadd -r appgroup && useradd -r -g appgroup appuser
USER appuser

4. RUN-Befehle zusammenfassen und bereinigen

# Schlecht: drei Layer, Cache bleibt in Layer 1
RUN apt-get update
RUN apt-get install -y curl
RUN rm -rf /var/lib/apt/lists/*

# Gut: ein Layer, Bereinigung im selben Schritt
RUN apt-get update \
    && apt-get install -y --no-install-recommends curl \
    && rm -rf /var/lib/apt/lists/*

5. HEALTHCHECK definieren

Docker und Container-Orchestratoren können Container auf Gesundheit prüfen — aber nur wenn ein Healthcheck definiert ist.

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

Ohne Healthcheck gilt ein Container mit dem Status running als gesund — auch wenn die Anwendung intern hängt.

6. Exec Form für CMD und ENTRYPOINT

# Shell Form: PID 1 ist /bin/sh, Signale kommen nicht an
CMD node index.js

# Exec Form: PID 1 ist node, SIGTERM wird korrekt empfangen
CMD ["node", "index.js"]

7. Instructions nach Änderungshäufigkeit sortieren

Was sich selten ändert, gehört nach oben (Basis-Image, System-Pakete, Dependencies). Was sich oft ändert (Quellcode), ans Ende. So bleibt der Layer-Cache so lange wie möglich gültig.

8. Images labeln

LABEL maintainer="team@example.com"
LABEL version="2.1.4"
LABEL description="API server for product service"

Labels sind über docker inspect abrufbar und helfen bei der Verwaltung von Images in Registries.

9. .dockerignore pflegen

Kein .git, kein node_modules, keine .env-Dateien im Build-Kontext. Weniger Kontext = schnellerer Build und keine versehentlichen Secrets im Image.