Ich habe eine fehlerhafte Version auf Azure Kubernetes Service (AKS) ausgerollt: Ihre Readiness-Prüfung antwortete mit 404. Zehn Minuten lang schlug kein einziger Aufruf fehl. Dann meldete kubectl, der Rollout sei gescheitert, und Kubernetes unternahm nichts.
Dieser Beitrag zeigt, was ein Rolling Update mit einer Version macht, die nie bereit wird, wo der Fehler sichtbar wird und warum das Zurückrollen Ihre Aufgabe ist. Alles stammt aus der Übung des Microsoft-Learn-Moduls, ausgeführt in meinem eigenen Cluster.
Das Wichtigste
- Der alte Pod bedient weiter. Bei einem Replikat darf ein Rolling Update einen zusätzlichen Pod starten und keinen wegnehmen. Der neue Pod startet neben dem alten, und der alte bleibt, bis der neue bereit ist. Meiner wurde es nie, und der Client hat keinen einzigen Fehler gesehen.
kubectl get deploymentsieht gesund aus. READY 1/1 zählte den alten Pod. Der neue Pod stand auf Running 0/1 mit 0 Neustarts, und der Grund stand nur in den Events:Readiness probe failed: HTTP probe failed with statuscode: 404.- Nach zehn Minuten meldet Kubernetes nur. Nach
progressDeadlineSeconds(standardmäßig 600) bekommt die ConditionProgressingdes Deployments den GrundProgressDeadlineExceeded, undkubectl rollout statusendet mit einem Fehler. Zurückgerollt wird nichts; beide Pods bleiben. - Das Undo ist Ihre Aufgabe, und mehr Replikate reißen ein größeres Loch.
kubectl rollout undostellte das alte Pod-Template sofort wieder her. Mit vier Replikaten nahm dieselbe fehlerhafte Version sofort einen alten Pod weg: READY 3/4, solange der Rollout hängt.
Die Übergabe: der neue Pod neben dem alten
In der Übung läuft eine kleine Python-API auf AKS. Ein Deployment hält ein Replikat davon am Laufen, hinter einem Service, der stabilen Adresse, die Aufrufe auf die Pods verteilt. Dann macht die Übung sie absichtlich kaputt: Die Readiness-Probe, die Prüfung, die sagt „ich bin bereit für Traffic“, fragt einen Pfad ab, den es nicht gibt.
readinessProbe:httpGet:path: /invalid-pathport: 8000initialDelaySeconds: 5periodSeconds: 10
Die Liveness-Probe in derselben Datei prüft weiter /healthz. Ich habe die Datei angewendet und die Pods mit einem kleinen eigenen Skript beobachtet, das jede Änderung ausgibt:
> kubectl apply -f k8s/probe-failure-deployment.yamldeployment.apps/api-deployment configured> python pods.py --secs 400.3s api-deployment-695945c854-nx6qj Running 1/1 restarts 00.3s api-deployment-6b4f47c8b7-6m9bb ContainerCreating 0/1 restarts 02.5s api-deployment-6b4f47c8b7-6m9bb Running 0/1 restarts 0
Der neue Pod lief, wurde aber nie bereit. Der alte blieb bei 1/1. Ein Client-Pod im Cluster rief den Service einmal pro Sekunde auf, wie ein Benutzer, und jede Antwort kam von dem Pod, der um 13:58 gestartet war, dem alten:
> kubectl logs client --tail 414:07:06 200 pod started 13:58:45.0514:07:07 200 pod started 13:58:45.0514:07:08 200 pod started 13:58:45.0514:07:09 200 pod started 13:58:45.05
Warum? Ein Rolling Update folgt zwei Einstellungen, standardmäßig je ein Viertel der Replikate:
| Einstellung | Standard | Bei 1 Replikat | Bei 4 Replikaten |
|---|---|---|---|
maxSurge: zusätzliche Pods während des Rollouts (aufgerundet) | 25 % | 1 | 1 |
maxUnavailable: Pods, die fehlen dürfen (abgerundet) | 25 % | 0 | 1 |
Bei einem Replikat darf der Rollout einen zusätzlichen Pod starten, aber keinen wegnehmen. Der alte Pod bleibt also, bis der neue bereit ist, und ein Pod bekommt erst Traffic vom Service, wenn er bereit ist.
Wo steht der Fehler?
Der übliche erste Blick gilt dem Deployment selbst: wie viele seiner Pods bereit, aktuell und verfügbar sind. Der neue Pod war 42 Sekunden alt und hatte bis dahin jede Prüfung nicht bestanden:
> kubectl get deployment api-deploymentNAME READY UP-TO-DATE AVAILABLE AGEapi-deployment 1/1 1 1 8m30s
Es sieht völlig gesund aus, weil es bereite Pods zählt, und der bereite ist der alte Pod. Die Pod-Liste zeigt den neuen Pod mit 0/1 und null Neustarts: Nur die Readiness-Probe schlägt fehl, die Liveness-Probe, die einen Container neu startet, besteht weiter.
> kubectl get podsNAME READY STATUS RESTARTS AGEapi-deployment-695945c854-nx6qj 1/1 Running 0 8m30sapi-deployment-6b4f47c8b7-6m9bb 0/1 Running 0 42sclient 1/1 Running 0 8m11s
Der Grund steht in den Events, den Notizen des Clusters darüber, was mit jedem Objekt passiert ist. Eine fehlgeschlagene Readiness-Probe ist ein Event mit dem Grund Unhealthy, alle zehn Sekunden aufs Neue:
> kubectl get events --field-selector reason=UnhealthyLAST SEEN TYPE REASON OBJECT MESSAGE2s Warning Unhealthy pod/api-deployment-6b4f47c8b7-6m9bb Readiness probe failed: HTTP probe failed with statuscode: 404
Dann habe ich kubectl dreißig Sekunden auf den Rollout warten lassen. Es lief in den Timeout, mit einem alten Replikat „pending termination“: Der Rollout wartete darauf, dass der alte Pod gehen darf.
> kubectl rollout status deployment api-deployment --timeout 30sWaiting for deployment "api-deployment" rollout to finish: 1 old replicas are pending termination...error: timed out waiting for the condition
Zehn Minuten später: zurückgerollt?
Ein Deployment hat eine Frist für den Fortschritt: progressDeadlineSeconds, standardmäßig 600 Sekunden, und Sie können sie im Deployment kürzer setzen. Macht der Rollout so lange keinen Fortschritt, wird das Deployment als gescheitert markiert. Ich habe denselben Befehl ohne Timeout ausgeführt und warten lassen:
> kubectl rollout status deployment api-deploymentWaiting for deployment "api-deployment" rollout to finish: 1 old replicas are pending termination...error: deployment "api-deployment" exceeded its progress deadline
Das kam etwa zehn Minuten, nachdem ich die fehlerhafte Version angewendet hatte. Hat Kubernetes sie zurückgerollt? Nein.
> kubectl get podsNAME READY STATUS RESTARTS AGEapi-deployment-695945c854-nx6qj 1/1 Running 0 17mapi-deployment-6b4f47c8b7-6m9bb 0/1 Running 0 10mclient 1/1 Running 0 17m
Beide Pods waren noch da. Das Log des Clients der letzten zwölf Minuten, der ganze hängende Rollout und etwas davor, enthielt 0 fehlgeschlagene und 718 beantwortete Aufrufe. Das Deployment meldet den Fehlschlag nur, in seiner Status-Condition Progressing:
> kubectl get deployment api-deployment -o jsonpath="{.status.conditions[1].reason}"ProgressDeadlineExceeded
Das ist alles. Die Kubernetes-Dokumentation sagt es deutlich: Bei einem hängenden Rollout unternimmt Kubernetes nichts außer dieser Meldung. Es versucht es weiter, und der alte Pod bedient weiter, so lange Sie es zulassen. Release-Werkzeuge über Kubernetes können einen gescheiterten Rollout erkennen und für Sie zurückrollen. Kubernetes selbst tut es nicht.
Undo, und drei Fehler
kubectl rollout undo stellt das vorherige Pod-Template wieder her, die Beschreibung der Pods im Deployment:
> kubectl rollout undo deployment api-deploymentdeployment.apps/api-deployment rolled back> kubectl rollout status deployment api-deployment --timeout 120sdeployment "api-deployment" successfully rolled out
Das war sofort fertig (0,6 s), weil der alte Pod nie gegangen war. kubectl warnte außerdem, dass ein Undo die Annotation last-applied-configuration eines mit kubectl apply verwalteten Deployments nicht aktualisiert; das nächste apply sollte also aus einem Manifest kommen, das funktioniert.
Drei Fehler machen einen hängenden Rollout schlimmer:
- Das Deployment nur auf einen Blick prüfen. READY 1/1 war der alte Pod. Sehen Sie sich die Pods und die Events an.
- Ohne Timeout warten. In einer Pipeline ist
kubectl rollout statusIhr Gate: Es endet mit einem Fehlercode, wenn der Rollout scheitert, sodass die Pipeline reagieren kann. Geben Sie ihm einen Timeout, der zu Ihrer App passt, hier zwei Minuten, und führen Sie das Undo in derselben Zeile aus, damit eine fehlerhafte Version nie zehn Minuten herumsteht:
kubectl rollout status deployment api-deployment --timeout 120s ||kubectl rollout undo deployment api-deployment
- Derselbe falsche Pfad für beide Probes. Hier war nur die Readiness-Probe falsch. Stünde die Liveness-Probe auch darauf, würde das Kubelet, der Agent auf dem Node, den neuen Pod wieder und wieder neu starten: eine Crash-Schleife zusätzlich zum hängenden Rollout.
Derselbe Fehler mit vier Replikaten
Ein Viertel von vier ist eins: ein Pod zusätzlich und ein Pod weg. Ich habe das Deployment auf vier skaliert, dieselbe fehlerhafte Version noch einmal angewendet und die Pods mit demselben Skript beobachtet:
> python pods.py --secs 400.3s api-deployment-695945c854-56gl2 Terminating 1/1 restarts 00.3s api-deployment-695945c854-8h7sh Running 1/1 restarts 00.3s api-deployment-695945c854-9xct9 Running 1/1 restarts 00.3s api-deployment-695945c854-nx6qj Running 1/1 restarts 00.3s api-deployment-6b4f47c8b7-dfhtx ContainerCreating 0/1 restarts 00.3s api-deployment-6b4f47c8b7-ljp88 ContainerCreating 0/1 restarts 02.5s api-deployment-6b4f47c8b7-dfhtx Running 0/1 restarts 02.5s api-deployment-6b4f47c8b7-ljp88 Running 0/1 restarts 02.5s api-deployment-695945c854-56gl2 gone> kubectl get deployment api-deploymentNAME READY UP-TO-DATE AVAILABLE AGEapi-deployment 3/4 2 3 18m
Ein alter Pod wurde schon nach einer Drittelsekunde beendet. Der Pod, der gegangen ist, braucht ebenfalls einen Ersatz, also starteten zwei neue Pods, und beide blieben bei 0/1 hängen. Bereit 3/4: ein Viertel der Kapazität weg, solange der Rollout hängt. Der Client bekam weiter seine Antworten, von den drei alten Pods. Niemand merkt es, bis der Traffic wächst und drei Pods nicht reichen. Bei einem hängenden Rollout bedeuten mehr Replikate nicht mehr Sicherheit, sondern ein größeres Loch.
Was beim Ausführen passiert ist
Getestet am 2. November 2026 in meinem eigenen Azure-Abonnement (AKS 1.36 in westeurope, Azure CLI 2.88.0, kubectl 1.36); danach wurde alles gelöscht. Der Cluster hatte einen Node vom Typ Standard_D2s_v5 mit angebundener Registry, wie in der Übung. Die fehlerhafte Version ging um 14:06:25 UTC hinein; kubectl rollout status ohne Timeout wartete 526,8 s und meldete die verpasste Frist um 14:16:27. Das Warten mit 30 Sekunden dauerte 30,4 s, und beide Wartebefehle endeten mit Exit-Code 1. Das Undo dauerte bei einem Replikat 0,6 s. Mit vier Replikaten dauerten das Hochskalieren und das Undo je 11,8 s, danach waren wieder vier Pods der alten Version bereit, einer davon neu. Die Zahl der Aufrufe stammt aus dem Log des Clients (kubectl logs client --since=12m, gezählt mit Select-String in PowerShell).
Was das Video weglässt
minReadySecondsund das Pausieren eines Rollouts mitkubectl rollout pause/resume.- Release-Werkzeuge, die für Sie zurückrollen, etwa Argo Rollouts oder Flagger.
- Fehlschlagende Liveness-Probes (eine Crash-Schleife) und Startup-Probes.
- Die Reparatur der Probe mit
kubectl edit, wie in der Übung: Wie das Undo startet sie einen neuen Rollout mit einem Template, das funktioniert.
Weiterführende Links
- Microsoft-Learn-Modul: Monitor and troubleshoot applications on Azure Kubernetes Service
- Deployments und Failed Deployment (Kubernetes-Dokumentation)
- Configure Liveness, Readiness and Startup Probes (Kubernetes-Dokumentation)



