- Authors

- Name
- Phillip Pham
- @ddppham
Docker und Kubernetes: Grundlagen, Zusammenspiel und Einstieg in die Container-Orchestrierung
TL;DR
- Docker baut und verpackt Anwendungen in Container. Kubernetes verwaltet und orchestriert diese Container im Cluster.
- Container sind keine leichtgewichtigen VMs -- sie teilen sich den Host-Kernel und isolieren nur den Userspace (Namespaces, cgroups).
- Ein Kubernetes-Deployment beschreibt den Soll-Zustand deklarativ in YAML. Kubernetes sorgt dafuer, dass der Ist-Zustand dem entspricht.
- Fuer den Einstieg reichen drei Konzepte: Pod, Deployment, Service. Alles andere kommt spaeter.
- Managed Kubernetes (EKS, AKS, GKE) nimmt die Komplexitaet der Control Plane ab. Fuer lokale Tests eignet sich kind oder k3d.
Docker: Was Container wirklich sind
Ein Docker-Container ist kein Mini-Server und keine leichtgewichtige VM. Ein Container ist ein isolierter Prozess, der auf dem Host-Kernel laeuft. Die Isolation basiert auf zwei Linux-Kernel-Features:
- Namespaces trennen die Sicht auf Prozesse, Netzwerk, Dateisystem und User-IDs
- cgroups begrenzen CPU, RAM und I/O pro Container
Ein Docker-Image ist ein Schichtensystem (Layer). Jede Zeile im Dockerfile erzeugt einen neuen Layer. Gleiche Layer werden zwischen Images geteilt, was Speicher und Download-Zeiten spart.
Dockerfile-Beispiel: Multi-Stage Build
Multi-Stage Builds trennen die Build-Umgebung von der Runtime-Umgebung. Das Ergebnis ist ein deutlich kleineres Image.
# Build Stage
FROM golang:1.22 AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o /app/server .
# Runtime Stage
FROM gcr.io/distroless/static-debian12:nonroot
COPY /app/server /server
EXPOSE 8080
USER nonroot:nonroot
ENTRYPOINT ["/server"]
Wichtige Best Practices fuer Docker-Images:
| Praxis | Warum |
|---|---|
| Multi-Stage Builds | Kleinere Images, keine Build-Tools in Produktion |
| Distroless oder Alpine als Basis | Weniger Pakete = weniger Angriffsflaeche |
USER nonroot | Container laeuft nicht als Root |
.dockerignore pflegen | Verhindert, dass Secrets oder Build-Artefakte ins Image gelangen |
Pinned Versions (golang:1.22, nicht golang:latest) | Reproduzierbare Builds |
Kubernetes: Container im Cluster verwalten
Docker baut Container. Kubernetes verwaltet sie. Auf einem einzelnen Server reicht Docker. Sobald mehrere Server, Skalierung und Hochverfuegbarkeit gefragt sind, braucht man einen Orchestrierer.
Kubernetes loest konkret diese Probleme:
- Scheduling: Auf welchem Node laeuft welcher Container?
- Scaling: Automatisch mehr Container starten, wenn die Last steigt
- Self-Healing: Abgestuerzte Container automatisch neu starten
- Service Discovery: Container finden sich gegenseitig ueber DNS
- Rolling Updates: Neue Versionen ohne Downtime deployen
Kubernetes-Architektur auf einen Blick
Ein Kubernetes-Cluster besteht aus der Control Plane und Worker Nodes.
Control Plane:
- API Server: Einziger Einstiegspunkt fuer alle Operationen (kubectl, Controller, Scheduler)
- etcd: Key-Value Store, haelt den gesamten Cluster-State
- Scheduler: Entscheidet, auf welchem Node ein Pod laeuft
- Controller Manager: Stellt sicher, dass Ist-Zustand = Soll-Zustand
Worker Nodes:
- kubelet: Agent auf jedem Node, startet und ueberwacht Pods
- Container Runtime: containerd oder CRI-O (Docker wird seit K8s 1.24 nicht mehr direkt unterstuetzt)
- kube-proxy: Netzwerk-Routing fuer Services
Die drei wichtigsten Kubernetes-Objekte
Fuer den Einstieg reichen drei Konzepte:
Pod: Die kleinste Einheit in Kubernetes. Ein Pod enthaelt einen oder mehrere Container, die sich Netzwerk und Storage teilen. In der Praxis laeuft fast immer ein Container pro Pod.
Deployment: Beschreibt den gewuenschten Zustand: Welches Image, wie viele Replicas, welche Ressourcen. Der Deployment Controller sorgt dafuer, dass dieser Zustand eingehalten wird.
Service: Gibt einer Gruppe von Pods eine stabile Netzwerkadresse. Pods sind fluechtig -- ein Service bleibt bestehen und leitet Traffic an die aktuellen Pods weiter.
Praxisbeispiel: Anwendung auf Kubernetes deployen
1. Deployment-Manifest
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
labels:
app: web
spec:
replicas: 3
selector:
matchLabels:
app: web
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: registry.example.com/web-app:1.4.2
ports:
- containerPort: 8080
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "512Mi"
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 10
periodSeconds: 15
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
Einige Details, die in vielen Tutorials fehlen:
requestsundlimitsmuessen gesetzt sein. Ohne Requests kann der Scheduler schlecht planen. Ohne Limits kann ein einzelner Container den ganzen Node lahmlegen.livenessProbeprueft, ob der Container noch lebt. Fehlschlag fuehrt zum Restart.readinessProbeprueft, ob der Container Traffic annehmen kann. Fehlschlag entfernt den Pod aus dem Service.maxUnavailable: 0bei Rolling Updates stellt sicher, dass waehrend eines Deployments nie weniger als die gewuenschte Anzahl Pods laufen.
2. Service und Ingress
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: web-app-svc
spec:
selector:
app: web
ports:
- port: 80
targetPort: 8080
protocol: TCP
type: ClusterIP
---
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web-app-ingress
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
ingressClassName: nginx
tls:
- hosts:
- app.example.com
secretName: web-app-tls
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-app-svc
port:
number: 80
3. Deployen und pruefen
# Manifeste anwenden
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
# Rollout-Status pruefen
kubectl rollout status deployment/web-app
# Pods ansehen
kubectl get pods -l app=web
# Logs eines Pods lesen
kubectl logs -l app=web --tail=50
# In einen Pod eine Shell oeffnen (Debugging)
kubectl exec -it deployment/web-app -- /bin/sh
Docker Compose vs. Kubernetes: Wann brauche ich was?
| Kriterium | Docker Compose | Kubernetes |
|---|---|---|
| Einsatzzweck | Lokale Entwicklung, kleine Projekte | Produktion, Multi-Node, Skalierung |
| Definitionsformat | docker-compose.yml | YAML-Manifeste (Deployment, Service, ...) |
| Skalierung | Manuell (docker compose up --scale) | Automatisch (HPA, VPA) |
| Self-Healing | Restart-Policy, kein echtes Rescheduling | Pod wird auf anderen Node verschoben |
| Service Discovery | Container-Name als DNS | CoreDNS, Service-Objekte |
| Komplexitaet | Niedrig | Hoch (aber Managed Services helfen) |
| Multi-Node | Nein (nur Docker Swarm) | Ja, Kern-Feature |
Docker Compose ist kein Kubernetes-Ersatz und Kubernetes ist kein Docker-Compose-Ersatz. Compose ist perfekt fuer die lokale Entwicklung, Kubernetes fuer den produktiven Betrieb.
Einstieg: Lokaler Kubernetes-Cluster in 5 Minuten
Fuer Tests und Lernen braucht man keinen Cloud-Account. Mit kind (Kubernetes in Docker) laesst sich ein vollstaendiger Cluster lokal starten:
# kind installieren (macOS)
brew install kind
# Cluster erstellen
kind create cluster --name dev
# Cluster pruefen
kubectl cluster-info --context kind-dev
kubectl get nodes
# Einen nginx deployen
kubectl create deployment nginx --image=nginx:1.25
kubectl expose deployment nginx --port=80 --type=NodePort
# Aufraeumen
kind delete cluster --name dev
Alternativen zu kind:
| Tool | Beschreibung | Ideal fuer |
|---|---|---|
| kind | Cluster in Docker-Containern | CI/CD, schnelle Tests |
| k3d | k3s (leichtgewichtiges K8s) in Docker | Lokale Entwicklung |
| minikube | VM-basiert, viele Addons | Einsteiger, Addons testen |
| Docker Desktop | Eingebauter K8s-Cluster | macOS/Windows-Entwickler |
Typische Stolperfallen beim Einstieg
latest Tag verwenden. image: myapp:latest fuehrt zu unvorhersehbaren Deployments. Kubernetes kann nicht erkennen, ob sich das Image geaendert hat. Immer einen konkreten Tag oder SHA nutzen.
Keine Resource Requests und Limits setzen. Ohne Limits kann ein Container unbegrenzt Speicher verbrauchen und den gesamten Node zum OOM-Kill zwingen. Ohne Requests plant der Scheduler blind.
Liveness Probe zu aggressiv konfiguriert. Eine Liveness Probe mit initialDelaySeconds: 0 und periodSeconds: 1 restartet Container, die einfach nur langsam starten. Besonders bei Java-Anwendungen mit langer Startup-Zeit ein Problem.
Kein Namespace-Konzept. Alles im default Namespace zu deployen macht ab zehn Services die Uebersicht unmoeglich. Mindestens pro Team oder Umgebung (dev, staging, prod) eigene Namespaces verwenden.
Kubernetes-Manifeste nicht versionieren. YAML-Dateien gehoeren genauso ins Git wie Anwendungscode. Aenderungen am Cluster sollten immer ueber Git und CI/CD laufen, nie manuell mit kubectl edit.
Naechste Schritte nach dem Einstieg
Wer die Grundlagen verstanden hat, sollte sich diese Themen als naechstes ansehen:
- Helm -- Package Manager fuer Kubernetes, vereinfacht das Management komplexer Deployments
- Namespaces und RBAC -- Zugriffssteuerung und Mandantentrennung
- Persistent Volumes -- Daten, die Pod-Neustarts ueberleben
- Horizontal Pod Autoscaler -- Automatische Skalierung basierend auf CPU/Memory oder Custom Metrics
- Network Policies -- Netzwerk-Segmentierung zwischen Pods
Weiterfuehrende Artikel
- Kubernetes Secrets Management mit Vault -- Sensible Daten sicher verwalten statt als Klartext in YAML
- Kubernetes Security Scanning automatisieren -- Container-Images auf Schwachstellen pruefen
- Kubernetes Cluster produktionsreif aufsetzen -- Von der Testumgebung zur Production-Baseline
- Kubernetes Monitoring mit Open Source -- Prometheus und Grafana fuer Cluster-Metriken
- Kubernetes Capacity Planning -- Ressourcen richtig dimensionieren
Wenn Sie Unterstuetzung beim Einstieg in Kubernetes brauchen -- sei es ein Workshop fuer Ihr Team, eine Architektur-Review oder Hilfe bei der Migration bestehender Anwendungen -- melden Sie sich gerne unter /kontakt.
Kubernetes-Beratung gesucht?
Wir helfen deutschen Unternehmen bei der Kubernetes-Implementierung, Migration und Optimierung. DSGVO-konform und praxiserprobt.
📖 Verwandte Artikel
Weitere interessante Beiträge zu ähnlichen Themen
Legacy-Modernisierung: Von VMs zu Kubernetes
Legacy-Anwendungen von VMs zu Kubernetes migrieren: Die 6 Rs der Modernisierung, Containerisierung einer 3-Tier-App und Datenbank-Strategien.
Node.js auf Kubernetes: Express-App deployen
Express-Apps auf Kubernetes deployen mit Multi-Stage Dockerfile, Graceful Shutdown, Resource Limits und HPA für stabile Production-Cluster.
Docker zu Kubernetes Migration: 10 häufige Fehler vermeiden
Die 10 häufigsten Fehler bei der Docker-zu-Kubernetes-Migration vermeiden: Resource Limits, Stateful Workloads, Health Checks und Networking praxisnah erklärt.
Podman vs Docker: Rootless Container im Vergleich
Podman und Docker im Vergleich: Rootless Container, daemonlose Architektur, Kubernetes-Integration und Migration-Guide mit praktischen Beispielen.
Kubernetes Automotive ASPICE 2026: Container für SDV und Compliance
Entdecken Sie, wie Kubernetes Automotive ASPICE 2026 Standards für die SDV-Entwicklung & Compliance revolutioniert. Effiziente Entwicklung, Tests und sichere Prozesse für OEMs in Deutschland – ein entscheidender Schritt für Kubernetes Compliance Deutschland.