I deployed a broken version to Azure Kubernetes Service (AKS): its readiness check answered 404. For ten minutes, not one call failed. Then kubectl said the rollout had failed, and Kubernetes did nothing about it.
This explainer shows what a rolling update does with a version that never gets ready, where the error shows up, and why rolling back is your job. Everything below comes from the Microsoft Learn exercise, run on my own cluster.
Key points
- The old pod keeps serving. With one replica, a rolling update may start one extra pod and take none away. The new pod starts next to the old one, and the old one stays until the new one is ready. Mine never was, and the client never saw an error.
kubectl get deploymentlooks healthy. READY 1/1 counted the old pod. The new pod was Running 0/1 with 0 restarts, and the reason was only in the events:Readiness probe failed: HTTP probe failed with statuscode: 404.- After ten minutes, Kubernetes only reports. After
progressDeadlineSeconds(600 by default) the Deployment'sProgressingcondition gets the reasonProgressDeadlineExceeded, andkubectl rollout statusexits with an error. Nothing is rolled back; both pods stay. - Undo is your job, and more replicas make a bigger hole.
kubectl rollout undoput the old pod template back at once. With four replicas, the same broken version took one old pod away immediately: READY 3/4 for as long as the rollout stays stuck.
The handover: the new pod next to the old one
In the exercise, a small Python API runs on AKS. A Deployment keeps one replica of it running, behind a Service, the stable address that spreads calls over the pods. Then the exercise breaks it on purpose: the readiness probe, the check that says "send me traffic", asks for a path that doesn't exist.
readinessProbe:httpGet:path: /invalid-pathport: 8000initialDelaySeconds: 5periodSeconds: 10
The liveness probe in the same file still checks /healthz. I applied the file and watched the pods with a small script of mine that prints every change:
> 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
The new pod ran, but never got ready. The old pod stayed at 1/1. A client pod inside the cluster called the Service once a second, like a user would, and every answer came from the pod that started at 13:58, the old one:
> 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
Why? A rolling update follows two settings, both a quarter of the replicas by default:
| Setting | Default | With 1 replica | With 4 replicas |
|---|---|---|---|
maxSurge: extra pods during the rollout (rounded up) | 25 % | 1 | 1 |
maxUnavailable: pods that may be missing (rounded down) | 25 % | 0 | 1 |
With one replica, the rollout may start one extra pod but may take none away. So the old pod stays until the new one is ready, and a pod only gets traffic from the Service once it is ready.
Where's the error?
The usual first look is the Deployment itself: how many of its pods are ready, up to date and available. The new pod was 42 seconds old and had failed every check so far:
> kubectl get deployment api-deploymentNAME READY UP-TO-DATE AVAILABLE AGEapi-deployment 1/1 1 1 8m30s
It looks perfectly healthy, because it counts ready pods, and the ready one is the old pod. The pod list shows the new pod at 0/1, with zero restarts: only the readiness probe fails, and the liveness probe, the one that restarts a container, still passes.
> 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
The reason is in the events, the cluster's notes about what happened to each object. A failed readiness probe is an event with the reason Unhealthy, every ten seconds again:
> 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
Then I asked kubectl to wait for the rollout, for thirty seconds. It timed out, with one old replica "pending termination": the rollout was waiting for the old pod to be allowed to go.
> 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
Ten minutes later: rolled back?
A Deployment has a progress deadline: progressDeadlineSeconds, 600 seconds by default, and you can make it shorter in the Deployment. If the rollout makes no progress for that long, the Deployment is marked as failed. I ran the same command without a timeout and let it wait:
> 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
That came about ten minutes after I had applied the broken version. Did Kubernetes roll it back? No.
> 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
Both pods were still there. The client's log for the last twelve minutes, the whole stuck rollout and a little before, held 0 failed calls and 718 answered ones. The Deployment only reports the failure, in its status condition Progressing:
> kubectl get deployment api-deployment -o jsonpath="{.status.conditions[1].reason}"ProgressDeadlineExceeded
That's all. The Kubernetes docs say it plainly: Kubernetes takes no action on a stalled rollout other than reporting this condition. It keeps trying, and the old pod keeps serving, for as long as you let it. Release tools on top of Kubernetes can watch for a failed rollout and roll back for you. Kubernetes itself doesn't.
Undo, and three mistakes
kubectl rollout undo puts the previous pod template back, the description of the pods inside the 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
It finished at once (0.6 s), because the old pod had never left. kubectl also warned that an undo does not update the last-applied-configuration annotation of a Deployment managed with kubectl apply, so the next apply should come from a manifest that works.
Three mistakes make a stuck rollout worse:
- Checking the Deployment at a glance. READY 1/1 was the old pod. Look at the pods and the events.
- Waiting without a timeout. In a pipeline,
kubectl rollout statusis your gate: it exits with an error code when the rollout fails, so the pipeline can act on it. Give it a timeout that fits your app, two minutes for this one, and run the undo in the same line, so a broken version never sits there for ten minutes:
kubectl rollout status deployment api-deployment --timeout 120s ||kubectl rollout undo deployment api-deployment
- The same wrong path for both probes. Here only the readiness probe was wrong. With the liveness probe on it too, the kubelet, the agent on the node, would restart the new pod again and again: a crash loop on top of the stuck rollout.
The same mistake with four replicas
A quarter of four is one: one pod extra, and one pod away. I scaled the Deployment to four, applied the same broken version again and watched the pods with the same script:
> 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
One old pod was already terminating a third of a second in. The pod that left needs a replacement too, so two new pods started, and both got stuck at 0/1. Ready 3/4: a quarter of the capacity gone, for as long as the rollout stays stuck. The client still got its answers, from the three old pods. Nobody notices, until the traffic grows and three pods aren't enough. With a stuck rollout, more replicas don't mean more safety: they mean a bigger hole.
What happened when I ran it
Tested on November 2, 2026 in my own Azure subscription (AKS 1.36 in westeurope, Azure CLI 2.88.0, kubectl 1.36); everything was deleted afterwards. The cluster had one Standard_D2s_v5 node with the registry attached, as in the exercise. The broken version went in at 14:06:25 UTC; kubectl rollout status without a timeout waited 526.8 s and reported the missed deadline at 14:16:27. The 30-second wait took 30.4 s, and both waits exited with code 1. The undo took 0.6 s with one replica. With four replicas, the scale-up and the undo each took 11.8 s, and afterwards four pods of the old version were ready again, one of them new. The call counts came from the client's own log (kubectl logs client --since=12m, counted with PowerShell's Select-String).
What the video leaves out
minReadySeconds, and pausing a rollout withkubectl rollout pause/resume.- Release tools that roll back for you, such as Argo Rollouts or Flagger.
- Liveness probe failures (a crash loop) and startup probes.
- Fixing the probe with
kubectl edit, as the exercise does: like the undo, it starts a new rollout with a template that works.
Further reading
- Microsoft Learn module: Monitor and troubleshoot applications on Azure Kubernetes Service
- Deployments and Failed Deployment (Kubernetes docs)
- Configure Liveness, Readiness and Startup Probes (Kubernetes docs)



