Ein Kubernetes Rolling Update tauscht die Pods eines Deployments nach und nach gegen eine neue Version aus, statt alle auf einmal zu ersetzen. Dadurch bleibt die Anwendung während des Updates erreichbar, solange genug alte Pods laufen, bis die neuen bereit sind. Geht dabei etwas schief, macht ein Rollback die Änderung rückgängig und bringt die vorherige Version zurück.
Für Entwickler und DevOps-Teams ist das der Vorgang, der über jedes Release entscheidet: Läuft er sauber durch, merkt niemand etwas vom Deployment. Hängt er, weil eine Konfiguration fehlt oder ein Health-Check nie grün wird, steht die Anwendung im schlimmsten Fall halb aktualisiert und halb alt gleichzeitig da.
Ich betreibe Kubernetes-Cluster in Produktion und habe das Kubernetes-Praxisbuch bei Rheinwerk geschrieben. Die Stellhebel und Fehlerbilder aus diesem Beitrag stammen aus echten Rollouts, nicht nur aus der Theorie. Alle meine Beiträge zu Kubernetes findest du gesammelt auf der Seite Kubernetes.
Deployment und ReplicaSet: wer den Rollout eigentlich steuert
Ein Rolling Update läuft nie direkt über einzelne Pods, sondern über zwei Objekte, die zusammenarbeiten. Das Deployment kennt die gewünschte Anzahl an Pods, die Update-Strategie und die Historie früherer Versionen. Das ReplicaSet ist das ausführende Objekt darunter: Es sorgt nur dafür, dass genau die Anzahl an Pods läuft, die ihm gerade zugewiesen ist.
Wenn du ein Deployment aktualisierst, zum Beispiel mit einem neuen Image, erzeugt Kubernetes im Hintergrund ein komplett neues ReplicaSet für die neue Version. Das alte ReplicaSet bleibt bestehen, wird aber schrittweise auf null Pods heruntergefahren, während das neue hochgefahren wird. Diese beiden ReplicaSets nebeneinander sind auch der Grund, warum ein Rollback so einfach ist: Die alte Pod-Spezifikation ist nicht weg, sie liegt nur gerade auf null Replicas.
Wie viele ReplicaSets Kubernetes für dich aufhebt, steuerst du über revisionHistoryLimit im Deployment. Der Standardwert reicht für die meisten Fälle, aber setze ihn nie auf null, sonst hast du kein Material mehr für ein Rollback über kubectl.
Rolling-Update-Strategie in Kubernetes: maxSurge und maxUnavailable
Kubernetes kennt zwei Strategien für ein Update. Recreate löscht zuerst alle laufenden Pods und startet danach die neuen, was garantiert zu einer Ausfallzeit führt und deshalb nur für Entwicklungsumgebungen mit knappen Ressourcen infrage kommt. RollingUpdate ist der Standard und tauscht Pods schrittweise aus, sodass deine Anwendung während des gesamten Updates erreichbar bleibt.
Zwei Werte steuern, wie vorsichtig oder aggressiv dieser Austausch abläuft:
| Option |
Bedeutung |
Standardwert |
| maxUnavailable |
wie viele Pods während des Updates maximal gleichzeitig fehlen dürfen |
25 % |
| maxSurge |
wie viele zusätzliche Pods über die Sollzahl hinaus kurzzeitig erlaubt sind |
25 % |
Beide Werte darfst du als feste Zahl oder als Prozentsatz angeben, und bei Prozentwerten rundet Kubernetes unterschiedlich: maxUnavailable ab, maxSurge auf. Ein Deployment mit drei Replicas und den Standardwerten landet damit bei maxUnavailable 0 und maxSurge 1. Es darf während des Updates also gar kein Pod fehlen, dafür läuft kurzzeitig ein zusätzlicher mit, insgesamt bis zu vier. Weil sich dieses Ergebnis mit jeder Änderung der Replica-Zahl verschiebt, setze ich maxUnavailable bei Anwendungen, in denen jeder ausfallende Pod spürbar ist, ausdrücklich auf 0 und lasse Kubernetes stattdessen über maxSurge zusätzliche Kapazität hochfahren, bevor ein alter Pod verschwindet.
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-backend
spec:
replicas: 4
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 1
selector:
matchLabels:
app: web-backend
template:
metadata:
labels:
app: web-backend
spec:
containers:
- name: web-backend
image: registry.example.com/web-backend:c3f1a9d
ports:
- containerPort: 8080
Nach dem Ausrollen verfolgst du den Fortschritt mit einem einzigen Befehl:
kubectl rollout status deployment/web-backend
Der Befehl blockiert, bis das Update abgeschlossen ist, und zeigt dir sofort, wenn ein Rollout hängen bleibt, statt immer wieder von Hand kubectl get pods auszuführen.
Ohne Readiness Probe kein Zero-Downtime-Update
Kubernetes tauscht Pods auch ohne jede Konfiguration aus, doch ohne eine Readiness Probe weiß es nicht, wann ein neuer Pod tatsächlich bereit ist, Anfragen zu bedienen. Ohne diese Information markiert Kubernetes einen Pod als verfügbar, sobald der Container gestartet ist, unabhängig davon, ob die Anwendung darin schon reagiert. Genau in diesem Fenster landen dann Anfragen bei einem Pod, der noch gar nicht antworten kann.
Eine Readiness Probe schließt diese Lücke: Erst wenn sie erfolgreich ist, nimmt der zugehörige Service den Pod ins Loadbalancing auf, und erst dann wertet das Deployment den neuen Pod als fertig ausgerollt. Schlägt die Probe fehl, wartet der Rollout, statt fälschlich weiterzumachen, und du siehst das sofort in kubectl rollout status. Wie du Readiness, Liveness und Startup Probes im Detail konfigurierst, steht in Liveness und Readiness Probes erklärt.
Ein Rolling Update ohne Readiness Probe funktioniert technisch, aber ohne die Garantie, die du eigentlich willst. Ich setze deshalb bei jeder produktiven Anwendung mindestens eine Readiness Probe, meist einen einfachen HTTP-Endpunkt, der erst dann 200 zurückgibt, wenn Datenbankverbindung und sonstige Abhängigkeiten stehen.
Rollback in der Praxis: rollout history und rollout undo
Zwei Befehle reichen, um dir einen Überblick über frühere Versionen zu verschaffen und zu einer davon zurückzukehren:
kubectl rollout history deployment/web-backend
kubectl rollout undo deployment/web-backend --to-revision=3
Ohne die Angabe einer Revision geht rollout undo einfach einen Schritt zurück zur vorherigen Version. Kubernetes führt dabei technisch dasselbe Verfahren aus wie bei einem normalen Update: Es hebt das alte ReplicaSet wieder hoch und fährt das aktuelle herunter, inklusive derselben Readiness-Prüfung und derselben Strategie-Parameter. Ein Rollback ist also kein Sonderfall, sondern ein Rolling Update in die andere Richtung.
Die Historie in rollout history zeigt dir standardmäßig nur Revisionsnummern ohne Kontext, was ein Rollback zur richtigen Version erschwert, sobald mehrere Änderungen zusammenkommen. Mit kubectl rollout history deployment/web-backend --revision=3 lässt du dir das komplette Pod-Template dieser Revision anzeigen und siehst so, was sich geändert hat.
Rollback über Git statt kubectl rollout undo
kubectl rollout undo ist in einer akuten Störung schnell zur Hand, doch in meinen eigenen Clustern nutze ich es kaum. Der Grund: Nach einem Rollback über kubectl weicht der Zustand im Cluster von dem ab, was in deinem Git-Repository als aktuell hinterlegt ist. Andere Entwickler sehen im Repository weiterhin die neue Version, während im Cluster längst wieder die alte läuft, und diese Lücke fällt oft erst beim nächsten Deployment unangenehm auf.
Und noch eine Grenze gehört dazu: Ein Rollback über alte ReplicaSets holt nur den Zustand des Deployments zurück, also Image, Umgebung und Konfiguration der Pods. Was deine Anwendung inzwischen außerhalb davon verändert hat, kommt nicht mit. Eine Datenbankmigration, die Spalten umbenannt hat, eine geschriebene Datei, ein verschickter Auftrag: dafür brauchst du einen eigenen Rückweg. Deshalb baue ich Migrationen so, dass die vorherige Anwendungsversion mit dem neuen Schema noch läuft.
Läuft dein Cluster über GitOps, etwa mit ArgoCD, ist der sauberere Weg ein Rollback im Repository selbst: den fehlerhaften Commit revertieren oder auf den Tag der vorherigen Version zurücksetzen und den GitOps-Controller den Rollout ausführen lassen. Damit bleibt Git durchgehend die Quelle der Wahrheit, die Historie zeigt exakt, wann und warum zurückgerollt wurde, und der nächste reguläre Sync überschreibt deinen Rollback nicht versehentlich wieder. Wie dieser Ablauf im Detail aussieht, beschreibe ich in GitOps mit ArgoCD: Deployments aus Git; die ArgoCD-Dokumentation erklärt die Sync- und Rollback-Mechanik im Detail.
kubectl rollout undo bleibt trotzdem sinnvoll, wenn gerade niemand Zeit hat, erst einen Commit zu bauen, und die Anwendung sofort wieder laufen muss. Nur solltest du danach den Git-Stand nachziehen, damit Repository und Cluster wieder übereinstimmen.
Häufige Fragen
Was ist der Unterschied zwischen Rolling Update und Recreate?
RollingUpdate tauscht Pods schrittweise aus und hält die Anwendung dabei erreichbar, Recreate löscht zuerst alle Pods und startet danach die neuen, was zu einer Ausfallzeit führt. RollingUpdate ist der Standard und für produktive Anwendungen fast immer die richtige Wahl.
Wie mache ich ein Rollback in Kubernetes?
Mit kubectl rollout undo deployment/<name> gehst du zur vorherigen Version zurück, mit dem Zusatz --to-revision=<nummer> zu einer bestimmten früheren Version. Läuft dein Cluster über GitOps, ist ein Revert im Git-Repository der sauberere Weg, weil Cluster und Repository dabei konsistent bleiben.
Was bedeuten maxSurge und maxUnavailable?
maxUnavailable begrenzt, wie viele Pods während eines Updates gleichzeitig fehlen dürfen, maxSurge begrenzt, wie viele zusätzliche Pods kurzzeitig über die Sollzahl hinaus erlaubt sind. Beide lassen sich als feste Zahl oder als Prozentsatz angeben und stehen standardmäßig auf 25 Prozent, wobei Kubernetes maxUnavailable abrundet und maxSurge aufrundet.
Warum hängt mein Rollout mitten im Update fest?
Am häufigsten, weil ein neuer Pod keine erfolgreiche Readiness Probe meldet, etwa wegen eines Konfigurationsfehlers oder einer nicht erreichbaren Abhängigkeit. Kubernetes wartet dann, statt den Rollout fälschlich als erfolgreich zu melden. kubectl describe pod auf einen der neuen Pods zeigt in der Regel sofort den Grund.
Warum nutzt du Git statt kubectl rollout undo für ein Rollback?
Weil ein Rollback per kubectl den Cluster vom Stand im Git-Repository entkoppelt: Der Cluster läuft dann auf einer alten Version, während das Repository weiterhin die neue zeigt. Ein Revert im Repository hält beide Stände synchron und dokumentiert das Rollback nachvollziehbar in der Commit-Historie.
Wie du weitermachst
Wenn du die Grundlagen des Deployment-Objekts noch einmal komplett durchgehen willst, findest du sie in Kubernetes Deployment: Rollout erklärt. Für die Readiness-, Liveness- und Startup-Probes, ohne die kein Rolling Update wirklich sicher ist, lohnt sich Liveness und Readiness Probes erklärt. Und wer Rollbacks künftig über Git statt über kubectl steuern will, findet den Einstieg in GitOps mit ArgoCD: Deployments aus Git.
Mein Vorschlag für heute: Nimm ein bestehendes Deployment, setze maxUnavailable testweise auf 0 und beobachte mit kubectl rollout status und kubectl get events, wie vorsichtig Kubernetes dadurch vorgeht. Ausführlich mit allen Beispielen, von den ReplicaSet-Grundlagen bis zu den Probe-Parametern, steht das in den Kapiteln 3 und 8 meines Kubernetes-Praxisbuchs bei Rheinwerk.