Ein eigenes Docker-Image bauen mit Dockerfile
Mit einem Dockerfile verpackst du deine eigene Anwendung in ein Image. Hier lernst du die wichtigsten Anweisungen, baust dein erstes Image und optimierst es mit Best Practices.
Im letzten Beitrag hast du fertige Images wie Nginx gestartet. Jetzt gehst du einen Schritt weiter und verpackst deine eigene Anwendung in ein Image. Das Werkzeug dafür ist das Dockerfile – eine einfache Textdatei mit Bauanweisungen. In diesem Beitrag lernst du die wichtigsten Anweisungen kennen und baust dein erstes eigenes Image.
Was ist ein Dockerfile?
Ein Dockerfile ist ein Rezept: Es beschreibt Schritt für Schritt, wie aus einem Basis-Image und deinem Code ein fertiges Image entsteht. Jede Zeile ist eine Anweisung. Docker arbeitet sie von oben nach unten ab und erzeugt für jeden Schritt eine sogenannte Schicht (Layer). Die Datei heißt einfach Dockerfile, ohne Endung.
Die wichtigsten Anweisungen
Ein paar Schlüsselwörter begegnen dir in fast jedem Dockerfile:
FROM– legt das Basis-Image fest.WORKDIR– setzt das Arbeitsverzeichnis im Container.COPY– kopiert Dateien von deinem Rechner ins Image.RUN– führt einen Befehl beim Bauen aus (z. B. Installation).CMD– legt fest, was beim Start des Containers ausgeführt wird.
Dein erstes Dockerfile
Stell dir vor, du hast eine kleine Node.js-Anwendung. Ein passendes Dockerfile könnte so aussehen:
# Basis-Image mit Node.js
FROM node:20-alpine
# Arbeitsverzeichnis im Container
WORKDIR /app
# Zuerst nur die Paketdateien kopieren
COPY package*.json ./
# Abhängigkeiten installieren
RUN npm install
# Restlichen Quellcode kopieren
COPY . .
# Port, den die App nutzt
EXPOSE 3000
# Startbefehl
CMD ["node", "index.js"]Beachte die Reihenfolge: Wir kopieren zuerst nur package*.json und installieren die Abhängigkeiten, bevor wir den restlichen Code kopieren. Das hat einen guten Grund, wie du gleich siehst.
Das Image bauen und starten
Liegt das Dockerfile im Projektordner, baust du das Image mit docker build:
# Image bauen und mit Namen versehen (Tag)
docker build -t meine-app:1.0 .
# Container aus dem Image starten
docker run -d -p 3000:3000 --name app meine-app:1.0Der Punkt am Ende von docker build ist wichtig: Er gibt den Build-Kontext an, also das Verzeichnis, aus dem Docker die Dateien liest. Mit -t meine-app:1.0 vergibst du Namen und Version.
Caching verstehen und nutzen
Docker speichert jede Schicht zwischen. Ändert sich eine Datei nicht, nutzt Docker beim nächsten Bauen die zwischengespeicherte Schicht – das spart enorm viel Zeit. Genau deshalb kopieren wir die package.json zuerst: Solange sich deine Abhängigkeiten nicht ändern, wird der teure Schritt npm install übersprungen.
Damit nicht unnötige Dateien ins Image wandern, legst du eine .dockerignore an:
# .dockerignore
node_modules
.git
*.log
.envSo bleiben dein lokales node_modules und sensible Dateien außen vor, und das Image bleibt schlank.
Multi-Stage-Builds für kleine Images
Für kompilierte Sprachen oder Build-Schritte lohnt sich ein Multi-Stage-Build. Dabei nutzt du eine Stage zum Bauen und kopierst nur das Ergebnis in ein schlankes Endbild:
# Stage 1: Bauen
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# Stage 2: Nur das Ergebnis übernehmen
FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80Das Endbild enthält nur den fertigen Build und einen kleinen Webserver – ohne die ganzen Build-Werkzeuge. So sparst du oft hunderte Megabyte.
Fazit
Mit einem Dockerfile verpackst du deine eigene Anwendung in ein portables Image. Du kennst jetzt die wichtigsten Anweisungen wie FROM, COPY, RUN und CMD und hast verstanden, warum die Reihenfolge wegen des Cachings entscheidend ist. Mit einer .dockerignore und Multi-Stage-Builds hältst du deine Images klein und sauber. Probiere als Nächstes aus, eines deiner eigenen Projekte zu containerisieren – am besten gleich mit Caching im Hinterkopf.