Docker hat sich zu einem unverzichtbaren Werkzeug in der modernen Softwareentwicklung entwickelt und ermöglicht es Teams, Anwendungen mit beispielloser Konsistenz und Einfachheit zu erstellen, bereitzustellen und auszuführen. Kernstück dieser Containerisierungsmagie ist das Dockerfile, ein einfaches, aber leistungsstarkes Skript, das als Bauplan für die Erstellung Ihrer Docker-Images dient.
Die Erstellung eines effektiven Dockerfile-Build-Prozesses ist mehr als nur eine technische Übung; sie ebnet den Weg zu schnelleren Entwicklungszyklen, kleineren und sichereren Anwendungsspeicherplätzen sowie zuverlässigeren Deployments. Egal, ob Sie Docker-Neuling sind oder Ihre Kenntnisse vertiefen möchten – dieser Leitfaden führt Sie durch die Grundlagen des Schreibens praktischer, effizienter und sicherer Dockerfiles.
Das Docker-Ökosystem verstehen: Eine kurze Auffrischung

Bevor wir uns mit Dockerfiles befassen, wollen wir kurz auf wichtige Docker-Konzepte eingehen:
- Images: Ein Image ist ein schlankes, eigenständiges, ausführbares Paket, das alles enthält, was zum Ausführen von Software benötigt wird, einschließlich des Codes, einer Laufzeitumgebung, Bibliotheken, Umgebungsvariablen und Konfigurationsdateien. Images sind unveränderliche Vorlagen.
- Container: Ein Container ist eine ausführbare Instanz eines Images. Sie können Container erstellen, starten, stoppen, verschieben oder löschen. Sie bieten isolierte Umgebungen für Ihre Anwendungen.
- Dockerfile: Darauf konzentrieren wir uns. Eine Dockerfile ist ein Textdokument, das eine Abfolge von Befehlen enthält, die Docker verwendet, um automatisch ein Image zu erstellen.
- Docker Hub/Registries: Dies sind Repositories zum Speichern und Teilen von Docker-Images, ähnlich wie GitHub für Code.
Ziel einer gut geschriebenen Dockerfile ist es, möglichst schlankes, schnell zu erstellendes und sicheres Image zu erzeugen
Docker-Build-Flags erklärt
- -t myapp:1.0 : Mit diesem Flag wird Ihrem Image ein Name (myapp) und eine Version (1.0) zugewiesen. Die Kennzeichnung erleichtert die Versionskontrolle und das spätere Auffinden bestimmter Image-Builds, insbesondere beim Deployment oder Pushen in eine Registry.
- . (Punkt) : Dies bezieht sich auf den Build-Kontext, das Verzeichnis, in dem Docker nach der Dockerfile und allen anderen für den Build benötigten Dateien (z. B. Dateien, die in das Image kopiert werden sollen) sucht.
Docker komprimiert den Inhalt dieses Verzeichnisses und sendet ihn an den Docker-Daemon. Wichtig: Während des Build-Prozesses kann nur auf Dateien innerhalb des Build-Kontexts zugegriffen werden.
Wesentliche Dockerfile-Anweisungen: Die Bausteine

Lassen Sie uns die gängigsten Anweisungen und deren effektive Anwendung genauer betrachten.
- AUS: Jede Dockerfile muss mit einer FROM-Anweisung beginnen. Diese gibt das Basis-Image an, auf dem Ihr Image aufgebaut wird.
- Zweck: Die Auswahl eines Ausgangspunktes, oft eines Betriebssystems (wie Ubuntu:22.04) oder einer vorkonfigurierten Anwendungslaufzeitumgebung (wie node:18-alpine).
- Beispiel : FROM python:3.9-slim
- Bewährte Vorgehensweise: Wählen Sie das minimale Basis-Image, das die Anforderungen Ihrer Anwendung erfüllt. Alpine-Versionen sind zwar sehr klein, verwenden aber musl libc, was zu Kompatibilitätsproblemen mit einigen C-abhängigen Paketen führen kann. Slim-Versionen stellen einen guten Kompromiss dar und bieten eine abgespeckte Version einer Standarddistribution (wie Debian) mit glibc.
- WORKDIR: Diese Einstellung legt das Arbeitsverzeichnis festArbeitsverzeichnis für alle nachfolgenden RUN-, CMD-, ENTRYPOINT-, COPY- und ADD-Anweisungen.
- Zweck: Die Definition des aktuellen Verzeichniskontexts innerhalb des Images für nachfolgende Dateivorgänge und Befehlsausführungen. Falls das Verzeichnis nicht existiert, erstellt Docker es.
- Beispiel: WORKDIR /usr/src/app
- Bewährte Vorgehensweise: Verwenden Sie absolute Pfade für WORKDIR. Das mehrmalige Wechseln von Verzeichnissen mit WORKDIR ist im Allgemeinen übersichtlicher als das Verketten von cd-Befehlen innerhalb von RUN-Anweisungen.
- KOPIE: Kopiert Dateien oder Verzeichnisse aus Ihrem Build-Kontext in das Dateisystem des Images.
- Zweck: Fügen Sie Ihren Anwendungscode, Konfigurationsdateien und andere notwendige Ressourcen zum Image hinzu.
- Beispiel:
Dockerfile
WORKDIR /usr/src/app
COPY package.json ./
COPY src/ ./src/
- Bewährte Vorgehensweise: Für einfaches Kopieren von Dateien ist COPY dem ADD vorzuziehen. COPY ist transparenter. ADD bietet zusätzliche Funktionen wie URL-Download und TAR-Entpackung, die weniger vorhersehbar sein können. Aus Gründen der Übersichtlichkeit und Sicherheit ist es oft besser, RUN mit curl, wget und tar zu verwenden, wenn Sie Dateien herunterladen und entpacken müssen.
- LAUFEN: Führt Befehle in einer neuen Ebene über dem aktuellen Image aus und speichert die Ergebnisse. Dies wird zum Installieren von Software, Erstellen von Verzeichnissen, Kompilieren von Code usw. verwendet.
- Zweck: Das Dateisystem des Images durch die Installation von Paketen, das Ausführen von Build-Skripten oder das Einrichten von Konfigurationen zu modifizieren.
- Beispiel:
Dockerfile
RUN apt-get update && apt-get install -y --no-install-recommends
nginx
curl
&& rm -rf /var/lib/apt/lists/*
- Bewährte Vorgehensweise: Verketten Sie zusammengehörige Befehle mit && und leeren Sie temporäre Dateien oder Paketmanager-Caches (z. B. mit `rm -rf /var/lib/apt/lists/*` für Debian/Ubuntu oder `yum clean all` für CentOS/RHEL) innerhalb desselben RUN-Befehls. Dadurch wird die Anzahl der Ebenen minimiert und die Image-Größe reduziert, da jeder RUN-Befehl eine neue Ebene erzeugt.
- ENV: Legt Umgebungsvariablen fest, die während des Build-Prozesses (nachdem sie definiert wurden) und beim Ausführen von Containern aus dem Image verfügbar sind.
- Zweck: Bereitstellung von Konfigurationswerten, Pfaden oder Einstellungen, die von Ihrer Anwendung oder Ihren Build-Skripten benötigt werden.
- Beispiel:
Dockerfile
ENV NODE_ENV=production
ENV APP_PORT=3000
- Bewährte Vorgehensweise: Verwenden Sie Umgebungsvariablen für nicht sensible Konfigurationsdaten. Verwenden Sie Laufzeit-Injektionsmethoden, anstatt Geheimnisse mithilfe von Umgebungsvariablen direkt in das Image einzubetten.
- ARG: Definiert eine Build-Zeitvariable, die Benutzer während des Docker-Builds mit dem Flag „--build-arg“ übergeben können.
- Zweck: Die Parametrisierung des Build-Prozesses zu ermöglichen, ohne die Dockerfile zu verändern.
- Beispiel: Dockerfile
Dockerfile
ARG APP_VERSION=1.0.0
ENV APP_VERSION_ENV=${APP_VERSION}
RUN echo “Building version ${APP_VERSION_ENV}”
- Erstellen mit: bash docker build --build-arg APP_VERSION=1.2.3 -t myapp.
- Hinweis: ARG-Variablen sind im laufenden Container nicht verfügbar, es sei denn, sie werden explizit als Umgebungsvariable festgelegt, wie oben gezeigt.
- EXPONIEREN: Informiert Docker darüber, dass der Container zur Laufzeit an den angegebenen Netzwerkports lauscht.
- Zweck: Dieses Dokument dient in erster Linie als Dokumentation für den Image-Ersteller und den Benutzer. Es veröffentlicht nicht die Portierung.
Beispiel:
Dockerfile
EXPOSE 8080
- Hinweis: Um den Port vom Host aus zugänglich zu machen, verwenden Sie den Parameter -p oder -P bei docker run (z. B. docker run -p 8080:8080 myimage).
- CMD Und EINSTIEGSPUNKT: Definiere, welcher Befehl beim Start eines Containers ausgeführt wird.
- CMD [“executable”, “param1”, “param2”] : Legt Standardwerte für einen laufenden Container fest. Diese Standardwerte können einfach durch Anhängen eines Befehls an docker run überschrieben werden. Sind mehrere CMDs vorhanden, wird nur der letzte berücksichtigt.
- ENTRYPOINT [“executable”, “param1”, “param2”] : Konfiguriert einen Container zur Ausführung als ausführbare Datei. Die an docker run übergebenen Argumente werden an den ENTRYPOINT-Befehl angehängt.
- Beispiel (typisches Muster):
Dockerfile
ENTRYPOINT [“python”, “app.py”] # Hauptbefehl
CMD [“–help”] # Standardargument, falls keines bei docker run angegeben wird
- Bewährte Vorgehensweise: Verwenden Sie CMD, wenn Sie einen einfach überschreibbaren Standardbefehl benötigen. Mit ENTRYPOINT erstellen Sie ein Image, das sich wie eine bestimmte ausführbare Datei verhält, wobei häufig CMD verwendet wird, um Standardargumente bereitzustellen. Für Webanwendungen sind CMD ["npm", "start"] oder CMD ["python", "manage.py", "runserver"] Standard.
Wichtige Best Practices für optimierte Dockerfiles

Das Schreiben einer funktionsfähigen Dockerfile ist nur der Anfang. Die Optimierung bringt erhebliche Vorteile.
- Den Build-Cache effektiv nutzen: Docker erstellt Images in Schichten und versucht, wenn möglich, Schichten aus vorherigen Builds wiederzuverwenden (Caching). Um die Cache-Treffer zu maximieren:
- Ordnen Sie die Anweisungen nach Häufigkeit der Änderungen, beginnend mit der Häufigkeit der Änderungen. Installieren Sie beispielsweise die Abhängigkeiten (die sich seltener ändern), bevor Sie den Quellcode Ihrer Anwendung kopieren (der sich häufig ändert).
Dockerfile
# Gutes Caching-Beispiel für eine Node.js-Anwendung
FROM node:18-alpine
WORKDIR /app
COPY package.json package-lock.json ./ # Abhängigkeiten ändern sich seltener
RUN npm ci --omit=dev # Diese Ebene wird zwischengespeichert, wenn sich die Paketdateien nicht ändern
COPY . . # Quellcode ändert sich häufig, daher ist dies der letzte
CMD [“node”, “server.js”]
- Halten Sie Ihre Bilder klein: Kleinere Images lassen sich schneller abrufen, übertragen und bereitstellen und bieten eine geringere Angriffsfläche.
- Verwenden Sie Minimal Base Images: Alpine-, Slim- oder Distroless-Varianten sind deutlich kleiner als vollständige OS-Images.
- Aufräumen in derselben RUN-Ebene: Nach der Installation von Paketen sollten unnötige Caches oder temporäre Dateien mit demselben RUN-Befehl entfernt werden. Zum Beispiel:
- Debian/Ubuntu: apt-get clean && rm -rf /var/lib/apt/lists/*
- CentOS/RHEL: yum clean all oder dnf clean all
- Alpine: rm -rf /var/cache/apk/*
- Setzen Sie auf mehrstufige Builds: Dies ist eine der effektivsten Methoden, um die Bildgröße zu reduzieren, insbesondere bei kompilierten Sprachen oder Anwendungen mit Build-Schritten (wie JavaScript-Frontends).
- Konzept: Verwenden Sie eine Stufe (einen FROM-Block) mit all Ihren Build-Tools und Entwicklungsabhängigkeiten, um Ihre Anwendung zu kompilieren/erstellen. Starten Sie dann eine neue Stufe mit einem minimalen Laufzeit-Basisimage und verwenden Sie COPY-from=
… um nur die notwendigen kompilierten Artefakte in diese endgültige, saubere Phase zu kopieren. - Beispiel (vereinfachte Go-Anwendung): Dockerfile
- Konzept: Verwenden Sie eine Stufe (einen FROM-Block) mit all Ihren Build-Tools und Entwicklungsabhängigkeiten, um Ihre Anwendung zu kompilieren/erstellen. Starten Sie dann eine neue Stufe mit einem minimalen Laufzeit-Basisimage und verwenden Sie COPY-from=
Dockerfile
# Phase 1: Build
FROM golang:1.20 AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp
# Phase 2: Runtime
FROM debian:bullseye-slim
WORKDIR /app
COPY –from=builder /app/myapp .
CMD [“./myapp”]
- Die Builder-Phase beinhaltet das Go SDK, das endgültige Image enthält jedoch nur die kompilierte Binärdatei und das minimale Alpine OS.
- Sicherheit hat Priorität:
- Als Benutzer ohne Root-Rechte ausführen: Container werden standardmäßig als Root ausgeführt. Dies stellt ein Sicherheitsrisiko dar. Erstellen Sie in Ihrer Dockerfile einen dedizierten Benutzer und eine Gruppe ohne Root-Rechte und verwenden Sie die Anweisung `USER`, um zu diesem zu wechseln.
Dockerfile
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
# … Dateien kopieren und den Besitzer auf appuser:appgroup ändern …
USER appuser
- Installieren Sie nur die unbedingt notwendigen Pakete: Jedes Paket stellt eine potenzielle Sicherheitslücke dar. Vermeiden Sie die Installation von Debugging-Tools oder Entwicklungshilfsmitteln in Produktionsumgebungen (verwenden Sie hierfür mehrstufige Builds).
- Geheimnisse nicht fest codieren: Vermeiden Sie es, Passwörter, API-Schlüssel oder andere Geheimnisse in Ihrer Dockerfile zu speichern (z. B. in Umgebungsvariablen). Verwenden Sie stattdessen Laufzeit-Injection-Methoden wie Docker-Secrets, Kubernetes-Secrets oder Umgebungsvariablen, die sicher zur Laufzeit bereitgestellt werden.
- Effektive Nutzung von .dockerignore: Erstellen Sie eine .dockerignore-Datei im Stammverzeichnis Ihres Build-Kontexts (auf derselben Ebene wie Ihre Dockerfile). Listen Sie darin Dateien und Verzeichnisse auf, die vom Docker-Daemon ausgeschlossen werden sollen (z. B. .git, node_modules, falls im Image installiert, lokale IDE-Konfigurationen, *.log).
- Vorteile: Der Docker-Build-Prozess wird beschleunigt , indem die Größe des Build-Kontexts reduziert und verhindert wird, dass sensible oder unnötige Dateien in das Image aufgenommen werden.
Über die Grundlagen hinaus: Weitere Verbesserungen

Sobald Sie mit dem oben Genannten vertraut sind, sollten Sie Folgendes für noch bessere Dockerfiles in Betracht ziehen:
- BuildKit: Dockers neuere Build-Engine, oft standardmäßig aktiviert. Sie bietet bessere Performance (parallele Builds), verbessertes Caching und erweiterte Funktionen wie Build-Secrets (RUN --mount=type=secret,…) und Cache-Mounts (RUN --mount=type=cache,…) für Paketmanager. Stellen Sie sicher, dass BuildKit aktiv ist, oder aktivieren Sie es mit DOCKER_BUILDKIT=1.
- Dockerfiles statisch analysieren: Verwenden Sie Tools wie Hadolint (hadolint Dockerfile), um Ihre Dockerfile vor dem Build statisch auf Fehler, Stilverstöße und die Einhaltung bewährter Verfahren zu analysieren.
Häufige Tipps zur schnellen Fehlerbehebung
- „Datei nicht gefunden“ beim Kopieren oder Hinzufügen : Überprüfen Sie den Quellpfad (er ist relativ zum Build-Kontext-Root) und stellen Sie sicher, dass die Datei nicht durch .dockerignore ausgeschlossen ist.
- Langsame Builds: Überprüfen Sie die Befehlsreihenfolge im Hinblick auf Cache-Optimierung. Fassen Sie RUN-Befehle nach Möglichkeit zusammen. Stellen Sie sicher, dass Ihre .dockerignore-Datei vollständig ist.
- Große Bilder: Verwenden Sie mehrstufige Builds! Bereinigen Sie die Ebenen in RUN. Wählen Sie minimale Basisbilder.
Dockerfiles in Ihrem DevOps-Workflow
Eine Dockerfile ist ein wichtiger Bestandteil von „Infrastructure as Code“
- Versionskontrolle: Speichern Sie Ihre Dockerfile immer zusammen mit Ihrem Anwendungscode in Ihrem Git-Repository.
- CI/CD-Integration: Automatisieren Sie Ihre Docker-Build- und Image-Push-Prozesse innerhalb Ihrer CI/CD-Pipelines (z. B. GitHub Actions, Jenkins, GitLab CI). Dies gewährleistet konsistente und reproduzierbare Builds und Deployments.
Fazit: Eine Grundlage für den Erfolg schaffen
Die Erstellung effektiver Dockerfiles ist eine Investition, die sich in Bezug auf Entwicklungsgeschwindigkeit, Betriebssicherheit und Anwendungssicherheit deutlich auszahlt. Durch das Beherrschen grundlegender Anweisungen, die Anwendung bewährter Methoden wie mehrstufiger Builds und sorgfältiger Verwaltung von Image-Layern sowie die Priorisierung von Sicherheit lassen sich schlanke, effiziente und robuste Docker-Images erstellen.
Dieser Leitfaden bietet eine solide Grundlage. Setzen Sie Ihre Docker-Reise fort, indem Sie weiter experimentieren, neue Möglichkeiten entdecken und Ihre Dockerfiles optimieren.
Sind Sie bereit, Ihre Docker- und DevOps-Praktiken auf die nächste Stufe zu heben?
von Seahawk Media sind darauf spezialisiert, Unternehmen dabei zu helfen, das volle Potenzial von Containerisierung, Cloud-Technologien und optimierten CI/CD-Pipelines auszuschöpfen. Unser Expertenteam unterstützt Sie gerne, wenn Sie Ihre Anwendungsbereitstellungen optimieren, die Sicherheit verbessern oder Ihren Entwicklungszyklus beschleunigen möchten.