- Authors

- Name
- Phillip Pham
- @ddppham
TL;DR
- Die meisten Migrationsfehler entstehen nicht bei der Containerisierung selbst, sondern beim Uebergang von Docker-Compose-Konventionen zu Kubernetes-Konzepten
- Fehlende Resource Limits sind der haeufigste Grund fuer instabile Cluster nach der Migration -- ein einzelner Container ohne Limits kann den gesamten Node lahmlegen
- Stateful Workloads (Datenbanken, Message Queues) erfordern PersistentVolumes, StatefulSets und durchdachte Backup-Strategien statt einfacher Volume-Mounts
- Health Checks sind in Kubernetes nicht optional: Ohne Liveness und Readiness Probes routet der Service Traffic an Container, die noch nicht bereit sind
- Eine schrittweise Migration mit parallelem Betrieb (Docker Compose + Kubernetes) reduziert das Risiko erheblich
Container Migration Fehler: 10 haeufige Probleme bei Docker-zu-Kubernetes
Die Containerisierung mit Docker war der erste Schritt. Jetzt steht die Migration zu Kubernetes an -- und hier scheitern ueberraschend viele Projekte. Nicht weil Kubernetes zu komplex ist, sondern weil Teams Docker-Compose-Gewohnheiten 1:1 uebertragen. Dieser Artikel zeigt die 10 haeufigsten Fehler und wie Sie sie vermeiden.
Fehler 1: Resource Limits nicht setzen
Das Problem
In Docker Compose laufen Container standardmaessig ohne Ressourcen-Beschraenkung. Das funktioniert auf einem einzelnen Host, weil der Kernel den Speicher verteilt. In Kubernetes fuehrt das zu einer Katastrophe: Der Scheduler kann Pods nicht sinnvoll platzieren, und ein einzelner Container ohne Memory Limit kann einen Out-of-Memory-Kill des gesamten Nodes ausloesen.
Die Loesung
# Falsch: Keine Limits (Docker-Compose-Gewohnheit)
containers:
- name: api
image: myapp:v1
# Richtig: Requests und Limits definiert
containers:
- name: api
image: myapp:v1
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
Faustregel: Requests auf den typischen Verbrauch setzen, Limits auf das Doppelte. Nach 2 Wochen Betrieb die tatsaechlichen Werte aus dem Monitoring ablesen und anpassen.
Requests und Limits sind kein Nice-to-have. Ohne Requests kann der Scheduler nicht entscheiden, auf welchem Node der Pod laufen soll. Ohne Limits gibt es kein Sicherheitsnetz bei Memory Leaks.
Fehler 2: Docker-Volumes direkt auf PersistentVolumes abbilden
Das Problem
In Docker Compose definieren Sie ein Volume mit einer Zeile:
# docker-compose.yml
volumes:
- ./data:/app/data
Teams uebertragen das auf Kubernetes mit einem hostPath-Volume. Das funktioniert auf einem Single-Node-Cluster, bricht aber sofort, wenn der Pod auf einem anderen Node neu gestartet wird -- die Daten sind weg.
Die Loesung
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: app-data
spec:
accessModes:
- ReadWriteOnce
storageClassName: managed-premium
resources:
requests:
storage: 10Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
template:
spec:
containers:
- name: api
volumeMounts:
- name: data
mountPath: /app/data
volumes:
- name: data
persistentVolumeClaim:
claimName: app-data
Verwenden Sie immer PersistentVolumeClaims mit einer StorageClass. Bei Managed Kubernetes (EKS, AKS, GKE) sind Storage Classes vorkonfiguriert. Fuer Datenbanken nutzen Sie StatefulSets statt Deployments, damit jeder Pod sein eigenes Volume erhaelt.
Fehler 3: Health Checks vergessen
Das Problem
Docker Compose hat einen optionalen healthcheck, den viele Teams ignorieren. In Kubernetes sind Health Checks kritisch: Ohne Readiness Probe routet der Service Traffic an Pods, die noch starten. Ohne Liveness Probe erkennt Kubernetes nicht, wenn eine Anwendung haengt.
Die Loesung
containers:
- name: api
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 15
periodSeconds: 10
failureThreshold: 3
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
failureThreshold: 3
startupProbe:
httpGet:
path: /healthz
port: 8080
failureThreshold: 30
periodSeconds: 10
Drei Probe-Typen verstehen:
- startupProbe: Gibt der Anwendung Zeit zum Starten (z.B. Java-Apps mit langer Startzeit)
- readinessProbe: Entscheidet, ob der Pod Traffic empfangen soll
- livenessProbe: Entscheidet, ob der Pod neu gestartet werden soll
Fuer eine tiefere Betrachtung von Health Checks im Vergleich zu Docker siehe Docker Healthcheck vs. Kubernetes Liveness.
Fehler 4: Networking-Unterschiede ignorieren
Das Problem
In Docker Compose erreichen Sie Services ueber ihren Service-Namen: http://api:8080. Das funktioniert in Kubernetes aehnlich, aber mit wichtigen Unterschieden:
- Service-Namen sind Namespace-spezifisch:
api.production.svc.cluster.local - Ports muessen im Service-Objekt definiert werden, nicht nur im Container
- Port-Mapping funktioniert anders als in Docker Compose
Die Loesung
apiVersion: v1
kind: Service
metadata:
name: api
namespace: production
spec:
selector:
app: api
ports:
- port: 8080 # Port, unter dem der Service erreichbar ist
targetPort: 8080 # Port im Container
protocol: TCP
Haeufige Netzwerk-Fehler:
| Docker Compose | Kubernetes | Loesung |
|---|---|---|
ports: "8080:8080" | Service + Ingress | Service fuer interne, Ingress fuer externe Erreichbarkeit |
links: [db] | Service Discovery via DNS | Automatisch ueber Service-Namen |
network_mode: host | hostNetwork: true | Vermeiden -- nutzen Sie NodePort oder LoadBalancer |
| Feste IPs | ClusterIP (dynamisch) | Immer DNS-Namen verwenden, nie IPs |
Fehler 5: Stateful Workloads als Deployments laufen lassen
Das Problem
Datenbanken, Message Queues und andere Stateful-Anwendungen laufen in Docker Compose als normale Services. In Kubernetes werden sie oft als Deployment migriert -- das ist falsch. Deployments garantieren keine stabile Netzwerk-Identitaet und keine geordnete Skalierung.
Die Loesung
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
spec:
serviceName: postgres
replicas: 3
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:16
ports:
- containerPort: 5432
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: managed-premium
resources:
requests:
storage: 50Gi
StatefulSet vs. Deployment:
| Eigenschaft | Deployment | StatefulSet |
|---|---|---|
| Pod-Namen | Zufaellig (api-7b9f4-xyz) | Stabil (postgres-0, postgres-1) |
| Skalierung | Parallel | Geordnet (0, 1, 2...) |
| Volumes | Geteilt oder keine | Eigenes Volume pro Pod |
| DNS | Nur ueber Service | Individuell pro Pod |
Bedenken Sie: Fuer Produktions-Datenbanken ist ein Managed Service (RDS, Cloud SQL, Azure Database) oft die bessere Wahl als ein selbst betriebenes StatefulSet.
Fehler 6: Environment Variables unsicher uebergeben
Das Problem
In Docker Compose stehen Umgebungsvariablen in einer .env-Datei oder direkt im docker-compose.yml. Teams uebertragen das auf Kubernetes und schreiben Passwoerter direkt in die Deployment-YAML:
# Falsch: Passwoerter im Klartext
env:
- name: DB_PASSWORD
value: "mein-super-geheimes-passwort"
Diese YAML-Dateien landen im Git-Repository, werden in CI/CD-Logs angezeigt und sind fuer jeden mit Cluster-Zugriff lesbar.
Die Loesung
# Richtig: Secrets referenzieren
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: app-secrets
key: db-password
Noch besser: Einen External Secrets Operator verwenden, der Secrets aus HashiCorp Vault, AWS Secrets Manager oder Azure Key Vault synchronisiert. So liegen Passwoerter nie im Kubernetes-Cluster.
Fuer Details zu Secrets-Management im Enterprise-Kontext siehe Kubernetes Security Hardening.
Fehler 7: Kein Graceful Shutdown implementieren
In Docker Compose druecken Sie Ctrl+C und der Container stoppt. In Kubernetes werden Pods regelmaessig neu gestartet -- durch Rolling Updates, Node-Drains oder OOM-Kills. Ohne SIGTERM-Handling gehen laufende Requests verloren.
spec:
terminationGracePeriodSeconds: 30
containers:
- name: api
lifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "sleep 5"]
Der preStop-Sleep gibt dem Ingress Controller Zeit, den Pod aus dem Routing zu entfernen, bevor SIGTERM gesendet wird. Die Anwendung hat dann terminationGracePeriodSeconds Zeit zum Herunterfahren, danach folgt SIGKILL.
Fehler 8: Logging nicht anpassen
Docker-Anwendungen schreiben oft in Log-Dateien (/var/log/app.log). In Kubernetes verschwinden Log-Dateien beim Pod-Neustart und fuellen das Node-Filesystem.
Regel: Schreibe auf stdout/stderr, nicht in Dateien. Kubernetes sammelt stdout/stderr automatisch (kubectl logs deployment/api). Fuer zentrale Log-Aggregation setzen Sie Fluent Bit (DaemonSet) mit einem Log-Backend (Elasticsearch, Loki) auf.
Fehler 9: ConfigMaps und Deployments nicht verknuepfen
Kubernetes startet Pods nicht automatisch neu, wenn sich eine referenzierte ConfigMap aendert. Drei Loesungen:
Option A: Checksumme als Annotation im Pod-Template -- bei jeder ConfigMap-Aenderung aendert sich die Annotation und erzwingt einen Rolling Update.
Option B: Den Stakater Reloader Controller installieren und die Annotation reloader.stakater.com/auto: "true" setzen. Der Reloader ueberwacht ConfigMaps und startet betroffene Deployments automatisch neu.
Option C: Versionierte ConfigMap-Namen mit Hash-Suffix (z.B. app-config-v2a3f) und Referenz im Deployment aktualisieren.
Fehler 10: Keine Rollback-Strategie
Das Problem
In Docker Compose rollt man zurueck, indem man das vorherige Image manuell startet. In Kubernetes existieren eingebaute Rollback-Mechanismen, die viele Teams nicht nutzen.
Die Loesung
# Deployment-Historie anzeigen
kubectl rollout history deployment/api
# Zum vorherigen Release zurueckrollen
kubectl rollout undo deployment/api
# Zu einer bestimmten Revision zurueckrollen
kubectl rollout undo deployment/api --to-revision=3
# Rollout-Status pruefen
kubectl rollout status deployment/api
Voraussetzung: Setzen Sie revisionHistoryLimit auf mindestens 5 (Standard: 10), damit genuegend alte ReplicaSets fuer ein Rollback vorgehalten werden.
Fuer eine umfassende Migrationsstrategie, die auch Legacy-Systeme abdeckt, empfehlen wir Kubernetes Migration Legacy Applications.
Migrations-Checkliste
Pre-Migration: Services inventarisiert, Stateful vs. Stateless identifiziert, Health-Check-Endpoints implementiert, Logging auf stdout/stderr umgestellt, SIGTERM-Handler eingebaut.
Kubernetes-Setup: Resource Requests/Limits definiert, PersistentVolumeClaims erstellt, Secrets in External Secrets Store, NetworkPolicies fuer Namespace-Isolation, Ingress konfiguriert.
Post-Migration: Monitoring und Alerting aktiv, Rollback getestet, Load-Tests durchgefuehrt, Backup-Strategie verifiziert, Runbooks erstellt.
Haeufige Fragen
Kann ich Docker Compose und Kubernetes parallel betreiben?
Ja, und das ist sogar empfehlenswert. Betreiben Sie die alte Docker-Compose-Umgebung parallel zur neuen Kubernetes-Umgebung. Migrieren Sie Service fuer Service und leiten Sie den Traffic schrittweise um. So koennen Sie bei Problemen sofort zurueckschalten.
Soll ich Kompose verwenden, um docker-compose.yml zu konvertieren?
Kompose ist ein Startpunkt, aber kein Produktions-Tool. Die generierten YAML-Dateien sind selten produktionsreif -- es fehlen Resource Limits, Health Checks und Security-Konfigurationen. Nutzen Sie Kompose als Grundlage und ueberarbeiten Sie die Ergebnisse manuell.
Wie migriere ich Datenbanken?
Datenbanken sind der schwierigste Teil. Drei Optionen: (1) Managed Database Service nutzen (empfohlen), (2) StatefulSet mit Operator (z.B. CloudNativePG fuer PostgreSQL), (3) Lift-and-Shift als StatefulSet ohne Operator (nur fuer einfache Setups). Planen Sie fuer die Datenbank-Migration extra Zeit ein.
Wie lange dauert eine Migration von Docker Compose zu Kubernetes?
Fuer 5-10 Services: 6-10 Wochen. Das umfasst Cluster-Setup, Anwendungsanpassung, Migration und Stabilisierung. Die reine Konvertierung der YAML-Dateien dauert Tage, nicht Wochen -- der Aufwand steckt in Health Checks, Monitoring, Security und Testing.
Naechste Schritte
- Inventarisieren Sie alle Services aus Ihrer
docker-compose.yml - Identifizieren Sie Stateful Services und planen Sie deren Storage-Strategie
- Implementieren Sie Health-Check-Endpoints in allen Anwendungen
- Starten Sie mit einem unkritischen Service als Pilot
- Fuer Compliance-Anforderungen bei der Migration beachten Sie unseren Artikel Kubernetes Compliance Luecken
Weiterfuehrende Artikel:
- Kubernetes Migration Legacy Applications
- Kubernetes Security Hardening
- Docker Healthcheck vs. Kubernetes Liveness
- Kubernetes Compliance: DSGVO und BSI
- Kubernetes Security Audit
Sie planen eine Container-Migration zu Kubernetes und moechten typische Fehler vermeiden? Sprechen Sie uns an fuer ein unverbindliches Assessment 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.
Kubernetes-Migration: Enterprise-Strategie planen
Enterprise-Migrationsstrategie für Kubernetes: Von der Application-Portfolio-Analyse über Migration-Waves bis zur Team-Readiness und Risikominimierung.
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.
ContainerCreating hängt: Ursachen finden und beheben
Kubernetes Pod bleibt im Status ContainerCreating? Die drei häufigsten Ursachen und Lösungen für Image Pull, Volume Mount und Init Container Probleme.
Kubernetes-Migration gescheitert: Projekt in 6 Wochen retten
Kubernetes-Migration gescheitert? Assessment-Framework, Rettungsplan und Entscheidungshilfe: Reparieren oder neu starten für IT-Leiter im Mittelstand.