Docker für Entwickler: Images, Container und Compose
Du hast von Docker und Containern gehört, aber wenn du es ausprobieren willst, wirst du von Begriffen wie Images, Containern, Volumes und Compose überwältigt. Oder vielleicht nutzt du Docker bereits, aber deine Images sind riesig, Builds sind langsam und die Verwaltung mehrerer Dienste fühlt sich wie eine lästige Pflicht an. Dieser Leitfaden räumt mit dem Lärm auf. Wir behandeln die Grundlagen von Docker für Entwickler und konzentrieren uns auf das, was du wirklich wissen musst, um containerisierte Anwendungen effizient zu erstellen, auszuführen und zu verwalten.
Warum Docker? Das Problem, das es löst
Vor Docker bedeutete die Bereitstellung einer App, die exakte Umgebung nachzubilden: bestimmte OS-Versionen, Bibliotheken und Konfigurationen. "Bei mir läuft es" wurde zum Klischee, weil es stimmte. Docker löst dies, indem es deine Anwendung mit ihren Abhängigkeiten in eine einzige, portable Einheit verpackt, die als Container bezeichnet wird. Container sind leichtgewichtig, isoliert und laufen konsistent überall dort, wo Docker installiert ist.
Images vs. Container: Der zentrale Unterschied
Ein Image ist eine schreibgeschützte Vorlage, die deinen Anwendungscode, die Laufzeitumgebung, Bibliotheken und Einstellungen enthält. Ein Container ist eine laufende Instanz eines Images. Stelle dir ein Image als Klasse und einen Container als Objekt vor. Du kannst mehrere Container aus demselben Image ausführen, jeder isoliert von den anderen.
Wie Images erstellt werden
Images werden aus einem Dockerfile erstellt, einer Textdatei mit Anweisungen. Hier ist ein minimales Beispiel für eine Node.js-App:
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
Jede Anweisung erzeugt eine Ebene (Layer). Ebenen werden zwischengespeichert. Wenn du also nur deinen Quellcode änderst, verwendet Docker die zwischengespeicherten Ebenen für Abhängigkeiten wieder, was Neuerstellungen schnell macht.
Erstellen und Ausführen
Erstelle das Image und führe einen Container aus:
docker build -t my-app .
docker run -p 3000:3000 my-app
Das -p-Flag ordnet Port 3000 auf deinem Host Port 3000 im Container zu.
Best Practices für effiziente Docker-Images
Große Images verlangsamen Builds, Pushes und Deployments. Befolge diese Praktiken, um Images schlank zu halten:
- Verwende offizielle Slim- oder Alpine-Basis-Images, wenn möglich. Zum Beispiel ist
node:18-alpineviel kleiner alsnode:18. - Nutze Multi-Stage-Builds, um Build-Zeit-Abhängigkeiten von der Laufzeitumgebung zu trennen. Dies hält das finale Image minimal.
- Kombiniere RUN-Befehle, um Ebenen zu reduzieren und Package-Manager-Caches in derselben Ebene zu bereinigen.
- Verwende eine .dockerignore-Datei, um unnötige Dateien (z. B. node_modules, .git) aus dem Build-Kontext auszuschließen.
Hier ist ein Multi-Stage-Dockerfile für eine Go-Anwendung:
# Build stage
FROM golang:1.21-alpine AS builder
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /app/main .
# Final stage
FROM alpine:latest
COPY --from=builder /app/main /main
CMD ["/main"]
Das finale Image enthält nur die kompilierte Binärdatei und Alpine, nicht die Go-Toolchain.
Datenverwaltung mit Volumes
Container sind flüchtig; wenn sie entfernt werden, gehen ihre Daten verloren. Volumes persistieren Daten außerhalb des Container-Lebenszyklus. Verwende sie für Datenbanken, Uploads oder jeden Zustand, der Neustarts überleben muss.
docker run -v my-data:/var/lib/postgresql/data postgres
Dies erstellt ein benanntes Volume my-data, das Docker verwaltet. Für die Entwicklung kannst du auch deinen Quellcode in den Container bind-mounten, um Live-Reloading zu ermöglichen:
docker run -v $(pwd):/app -p 3000:3000 my-app
Docker Compose: Mehrere Container orchestrieren
Echte Anwendungen benötigen oft mehrere Dienste: einen Webserver, eine Datenbank, einen Cache. Jeden mit docker run zu starten ist mühsam und fehleranfällig. Docker Compose ermöglicht es dir, Multi-Container-Apps mit einer einzigen YAML-Datei zu definieren und auszuführen.
Eine praktische docker-compose.yml
Hier ist eine Compose-Datei für eine Node.js-App mit PostgreSQL und Redis:
version: '3.8'
services:
web:
build: .
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgres://user:pass@db:5432/mydb
- REDIS_URL=redis://cache:6379
depends_on:
- db
- cache
db:
image: postgres:15-alpine
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: mydb
volumes:
- postgres_data:/var/lib/postgresql/data
cache:
image: redis:7-alpine
volumes:
postgres_data:
Führe docker compose up aus, um alle Dienste zu starten. Compose erstellt ein Standardnetzwerk, sodass Container sich gegenseitig über den Dienstnamen erreichen können (z. B. db, cache).
Häufige Compose-Befehle
docker compose up -d– im Detached-Modus starten (Hintergrund).docker compose logs -f web– Logs für einen Dienst verfolgen.docker compose exec web sh– eine Shell in einem laufenden Container öffnen.docker compose down– Container, Netzwerke und Volumes stoppen und entfernen (es sei denn, Volumes sind extern).
Wann Docker Compose vs. Kubernetes verwenden
Docker Compose ist ideal für lokale Entwicklung, Tests und kleine Deployments. Kubernetes eignet sich hervorragend für die Orchestrierung von Containern über Cluster hinweg für die Produktion im großen Maßstab. Für viele Entwickler ist Compose für die tägliche Arbeit ausreichend, und du kannst zu Kubernetes übergehen, wenn du Auto-Scaling, Selbstheilung und erweiterte Netzwerkfunktionen benötigst.
| Funktion | Docker Compose | Kubernetes |
|---|---|---|
| Anwendungsfall | Lokale Entwicklung, kleine Deployments | Produktionscluster |
| Komplexität | Niedrig | Hoch |
| Skalierung | Manuell | Automatisch |
| Lernkurve | Sanft | Steil |
FAQ
Was ist der Unterschied zwischen einem Image und einem Container?
Ein Image ist eine schreibgeschützte Vorlage mit deiner App und Abhängigkeiten. Ein Container ist eine laufende Instanz eines Images. Du kannst viele Container aus einem Image ausführen.
Wie reduziere ich die Docker-Image-Größe?
Verwende kleinere Basis-Images (wie Alpine), Multi-Stage-Builds, kombiniere RUN-Befehle und verwende eine .dockerignore-Datei, um unnötige Dateien auszuschließen.
Kann ich Docker Compose in der Produktion verwenden?
Ja, für kleine Deployments. Für größere, dynamische Umgebungen sind Kubernetes oder Docker Swarm besser geeignet.
Bereit, deinen Docker-Workflow zu optimieren? Schau dir unseren Nginx Log Analyzer an, um deine containerisierten Webserver zu debuggen und zu überwachen.