Wo Docker an seine Grenzen stößt
Docker ist kein Orchestrator
Docker ist eines der nützlichsten Werkzeuge der modernen Softwareentwicklung. Container starten, isolieren, verwalten – das macht Docker hervorragend. Die anderen Posts in dieser Reihe zeigen wie viel sich damit aufbauen lässt: Mailserver, Monitoring, Reverse Proxy, VPN-Anbindung.
Aber Docker ist, beim besten Willen, kein Orchestrator.
Was bedeutet das? Ein Orchestrator kennt den gewünschten Zustand eines Systems und sorgt kontinuierlich dafür, dass die Realität mit diesem Zustand übereinstimmt. Docker startet Container. Was danach passiert – ob sie laufen, ob sie skalieren, ob sie auf den richtigen Hosts landen – liegt in der Hand des Administrators.
Das ist für ein einzelnes System vollkommen ausreichend. Für einen wachsenden, kritischen Stack wird es zum Problem.
Die Punkte wo es eng wird
1. Updates ohne Ausfallzeit
Stell dir vor, eine Anwendung soll auf eine neue Version aktualisiert werden, während sie weiterläuft – fünf Instanzen, eine nach der anderen, ohne dass Nutzer einen Ausfall bemerken.
Mit Docker sieht das so aus:
# Neue Version starten
docker run app:v2
# Proxy-Konfiguration manuell anpassen
upstream backend {
server app1; # alt
server app2; # alt
server app3; # alt
server app4; # alt
server app5_new; # neu
}
# Proxy neu laden
nginx -s reload
# Alte Instanz entfernen
docker stop app1
Das funktioniert – einmal. Beim zweiten Durchlauf merkt man das Problem: Es gibt keinen zentralen Ort der weiß wie viele Instanzen gerade laufen, welche Version aktiv ist, und ob die neue Instanz überhaupt bereit ist bevor der Proxy umgestellt wird. Der Zustand verteilt sich auf Docker, die Proxy-Konfiguration und meistens noch ein Bash-Script das das Ganze zusammenhält.
Ein Rollback bei einem Fehler? Manuell. Die alte Version muss aktiv vorgehalten werden, kein automatischer Trigger bei Fehlern.
2. Speicher in verteilten Umgebungen
Ein Container bekommt ein Volume – einfach und verständlich:
docker run -v /mnt/nfs/data:/data meine-app
Solange ein Container auf einem Host läuft, ist das problemlos. Sobald mehrere Container auf mehrere Hosts verteilt sind, entstehen Fragen die Docker nicht beantwortet:
Wo liegen die Daten eigentlich? Welcher Container nutzt welches Volume? Wenn der Container auf einen anderen Host verschoben wird, muss der NFS-Share dort identisch gemountet sein – gleicher Pfad, gleiche Rechte, gleiche Konfiguration. Das muss jemand manuell sicherstellen, und es muss irgendwo dokumentiert sein.
Das größere Problem: Mehrere Container die gleichzeitig auf denselben Pfad schreiben, können sich gegenseitig die Daten korrumpieren. Docker hat dafür keine eingebaute Schutzschicht.
3. Health Checks ohne Konsequenz
Docker unterstützt Health Checks – ein Container kann als “healthy” oder “unhealthy” markiert werden:
HEALTHCHECK --interval=30s --timeout=10s \
CMD curl -f http://localhost:8080/health || exit 1
Das Problem ist was danach passiert: nichts. Ein “unhealthy” Container läuft weiter. Er bleibt im Load Balancer. Anfragen gehen weiterhin an ihn. Docker startet ihn nicht automatisch neu und entfernt ihn nicht aus der Rotation.
Der Health Check ist eine Information, keine Aktion. Was mit dieser Information gemacht wird, muss der Administrator entscheiden und implementieren.
4. Skalierung ist handarbeit
Eine Anwendung soll unter Last automatisch mehr Instanzen bekommen und bei geringer Last wieder weniger. Mit Docker bedeutet das:
- Container manuell starten
- Proxy-Konfiguration manuell anpassen
- Health prüfen
- Bei Entlastung: Container manuell stoppen, Proxy anpassen
Jeder dieser Schritte ist machbar. Zusammen ergeben sie einen Prozess der bei jeder Änderung manuell ausgeführt werden muss, fehleranfällig ist und nachts um drei Uhr besonders unangenehm wird.
5. Konfigurationsdrift
Das ist in der Praxis einer der schmerzhaftesten Punkte, weil er schleichend entsteht.
Server A läuft seit sechs Monaten. Zwischendurch wurden Konfigurationen angepasst, Volumes manuell gemountet, Umgebungsvariablen direkt im Terminal gesetzt. Server B wurde vor zwei Monaten aufgesetzt – ein bisschen anders, weil sich in der Zwischenzeit Dinge geändert haben.
Server A Server B
app:v1.3 app:v1.5
/mnt/data → /var/data /mnt/storage → /var/data
LOGLEVEL=warn LOGLEVEL=info
PORT=8080 PORT=8081
Die beiden Server verhalten sich unterschiedlich – und niemand weiß mehr genau warum. Bash-Scripts, CI/CD-Pipelines und manuelle Eingriffe haben über Zeit einen Zustand erzeugt, der nicht mehr vollständig dokumentiert ist.
Docker selbst hat kein Konzept von “gewünschtem Zustand”. Es startet was gestartet wird und lässt es laufen. Ob das dem entspricht was eigentlich laufen sollte, ist Sache des Menschen.
6. Netzwerk über mehrere Hosts
Auf einem einzelnen Host funktionieren Docker-Netzwerke hervorragend – Isolation, DNS-Auflösung, Traefik-Integration. Sobald Container auf verschiedene Hosts verteilt werden sollen, wird es kompliziert.
Docker Overlay Networks funktionieren nur mit Docker Swarm. Service Discovery über Hosts hinweg – also dass Container auf Host A automatisch Container auf Host B finden – braucht zusätzliche Werkzeuge wie Consul. Netzwerk-Policies, also Regeln die festlegen welcher Service welchen anderen Service ansprechen darf, gibt es in Docker nativ nicht.
Der typische Docker-Stack wächst zum Problem
Was als überschaubares Setup beginnt, sieht nach einiger Zeit oft so aus:
Docker
+ Docker Compose
+ Traefik / NGINX
+ Bash-Scripts für Updates
+ CI/CD-Pipeline als Klebstoff
+ Monitoring separat
+ Storage manuell verwaltet
+ Health Checks ohne Konsequenz
Jede dieser Schichten ist für sich sinnvoll. Zusammen ist das ein System mit verteilter Verantwortung und ohne zentrale Kontrolle. Wenn etwas schiefgeht, liegt die Antwort auf “was läuft gerade?” irgendwo zwischen Docker, dem Proxy und der Pipeline.
Wann ist Kubernetes die richtige Antwort?
Kubernetes ist nicht für jeden Anwendungsfall sinnvoll – und es ist kein leichter Einstieg. Aber es gibt klare Situationen wo der Wechsel Sinn macht:
Mehrere Hosts. Sobald Container auf mehr als einen Server verteilt werden sollen, ist Docker ohne Swarm überfordert. Kubernetes ist dafür gebaut.
Automatische Skalierung. Wenn eine Anwendung unter Last automatisch mehr Instanzen bekommen soll, ohne manuellen Eingriff, ist Kubernetes die richtige Wahl.
Kritische Verfügbarkeit. Wenn ein Ausfall ernsthafte Konsequenzen hat und automatische Reaktion auf fehlerhafte Container nötig ist – nicht nur eine Information darüber.
Größere Teams. Wenn mehrere Personen an denselben Diensten arbeiten, braucht es einen gemeinsamen, versionierten Zustand. Kubernetes-Manifeste in einem Repository sind dieser Zustand.
Viele Dienste. Ab einer gewissen Anzahl von Services wird der manuelle Overhead von Docker-Management größer als der Lernaufwand für Kubernetes.
Kubernetes ist nicht die Antwort auf alles
Ein Homelab mit fünf Diensten, ein kleiner Firmenserver, ein einzelner VPS – für diese Szenarien ist Kubernetes meistens überdimensioniert. Die Lernkurve ist steil, der Betrieb aufwendiger als Docker Compose, und die Mehrwerte greifen erst wenn die Probleme aus diesem Post tatsächlich auftreten.
Docker und Docker Compose sind für diese Größenordnung die richtige Wahl. Die Posts in dieser Serie zeigen wie weit man damit kommt.
Der entscheidende Moment zum Nachdenken kommt, wenn die Frage auftaucht: “Wer weiß eigentlich gerade was wirklich läuft?” Wenn die Antwort unsicher ist – dann ist die Grenze erreicht.
Kurz zusammengefasst
| Problem | Docker-Realität | Kubernetes-Ansatz |
|---|---|---|
| Rolling Updates | manuell, fehleranfällig | Deployment Controller |
| Skalierung | manuell + Proxy-Update | HorizontalPodAutoscaler |
| Health → Aktion | nur Information | Readiness & Liveness Probes |
| Storage-Management | Pfad-basiert, manuell | PersistentVolumeClaim |
| Multi-Host Netzwerk | Swarm oder Dritttools | CNI + DNS + NetworkPolicies |
| Konfigurationsdrift | kein Schutz | Desired State wird erzwungen |
| Zentraler Zustand | verteilt | eine API, ein Zustand |