Roll Back a Failed Deployment to a Known-Good Revision
Deployment `storefront` in namespace `release-room` has a failed rollout. Its approved release, `nginx:1.27.5`, is available in revision history. The desired replica count is three. The current rolling-update settings also allow too many replicas to become unavailable.
Live lab access
This scenario is included in Free Practice. Choose from 6 fixed labs with 5 shared sessions per week, automatic grading, hints, solutions, AI Lab Coach and saved progress.
Create an account for this free lab →
Explore the six free labs with AI Lab Coach →
Read the brief on any device. Use a desktop or laptop for the terminal lab. Nothing starts until you choose Start.
The task
Deployment storefront in namespace release-room has a failed rollout. Its approved release, nginx:1.27.5, is available in revision history. The desired replica count is three. The current rolling-update settings also allow too many replicas to become unavailable.
Requirements
1. Inspect rollout history and restore the approved release.
2. Configure a RollingUpdate strategy with maxUnavailable: 0 and maxSurge: 1.
3. Ensure three updated replicas are available on the approved image and no active pods remain on the failed image.
Keep the existing Deployment, its selector, and its desired replica count. The resulting workload state is graded; an equivalent safe recovery is accepted.
Original Prepium guide · Written for Kubernetes v1.35 and checked against the official documentation on 6 October 2026. Use a disposable practice cluster.
Deployment revisions, rolling-update arithmetic and a stalled rollout you can recover
Every time a Deployment's Pod template changes, the controller creates a new ReplicaSet and records it as a revision; older ReplicaSets are kept (ten by default) so you can return to them. How fast Pods are swapped is governed by two numbers, maxSurge and maxUnavailable, and how long the controller waits before declaring a rollout stuck is progressDeadlineSeconds. Recovering a bad release on the exam means reading the history, picking the right revision, and confirming the result rather than trusting the undo command's one-line reply.
revision 1 (ReplicaSet A, nginx:1.26-alpine)
revision 2 (ReplicaSet B, nginx:1.27-alpine)
revision 3 (ReplicaSet C, bad tag) ── stalled: Progressing=False, ProgressDeadlineExceeded
undo --to-revision=1 ──→ A's template comes back as the newest revision
1. Build a history with readable change causes
kubectl create namespace prepium-tutorial
kubectl -n prepium-tutorial create deployment ticker --image=nginx:1.26-alpine --replicas=4
kubectl -n prepium-tutorial annotate deployment ticker kubernetes.io/change-cause="initial 1.26"
C=$(kubectl -n prepium-tutorial get deploy ticker -o jsonpath='{.spec.template.spec.containers[0].name}')
kubectl -n prepium-tutorial set image deployment/ticker "$C=nginx:1.27-alpine"
kubectl -n prepium-tutorial annotate deployment ticker kubernetes.io/change-cause="upgrade to 1.27" --overwrite
kubectl -n prepium-tutorial rollout history deployment/ticker
The CHANGE-CAUSE column is copied from the kubernetes.io/change-cause annotation; without it the column shows <none>. The old --record flag is deprecated, so annotate instead. set image takes container=image pairs, which is why the container name is read first rather than guessed.
2. Set the strategy and understand the arithmetic
kubectl -n prepium-tutorial patch deployment ticker -p \
'{"spec":{"progressDeadlineSeconds":45,"strategy":{"rollingUpdate":{"maxSurge":2,"maxUnavailable":1}}}}'
kubectl -n prepium-tutorial rollout history deployment/ticker
With 4 replicas, maxSurge: 2 allows up to 6 Pods during an update and maxUnavailable: 1 keeps at least 3 available. Percentages are converted to Pod counts, with surge rounded up and unavailable rounded down, which is why the 25% defaults never take a single-replica Deployment offline. The two cannot both be 0, because then no Pod could ever be replaced. Notice the history did not grow: strategy and deadline sit outside the Pod template, so changing them creates no revision.
3. Ship a broken release and watch it stall
kubectl -n prepium-tutorial set image deployment/ticker "$C=nginx:0.0.0-missing"
kubectl -n prepium-tutorial annotate deployment ticker kubernetes.io/change-cause="bad tag" --overwrite
kubectl -n prepium-tutorial rollout status deployment/ticker; echo "exit=$?"
kubectl -n prepium-tutorial get deployment ticker -o jsonpath='{.status.conditions[?(@.type=="Progressing")].reason}{"\n"}'
kubectl -n prepium-tutorial get pods
The new Pods cannot pull their image. Three old Pods stay available, as maxUnavailable: 1 promised, so the application keeps serving. After 45 seconds without progress, rollout status returns a non-zero exit code and the Progressing condition reports ProgressDeadlineExceeded. Kubernetes does nothing else: there is no automatic rollback.
4. Choose a revision, then roll back
kubectl -n prepium-tutorial rollout history deployment/ticker --revision=1
kubectl -n prepium-tutorial rollout undo deployment/ticker --to-revision=1
kubectl -n prepium-tutorial rollout status deployment/ticker
kubectl -n prepium-tutorial get deployment ticker -o jsonpath='{.spec.template.spec.containers[0].image}{"\n"}'
kubectl -n prepium-tutorial rollout history deployment/ticker
--revision=N prints that revision's Pod template, so you confirm the image before restoring it. Plain undo would only step back one revision, to 1.27; --to-revision lets you skip further. A rollback updates the Deployment's revision, so the restored template appears as the newest entry in the history.
Common mistakes
- Trusting
rolled backas proof. Wait forrollout statusand check the image and READY counts; the restored template can still fail. - Expecting a strategy change to appear in history. Only Pod template changes create revisions.
- Setting both
maxSurgeandmaxUnavailableto 0. That combination is invalid. - Waiting for Kubernetes to undo a stalled rollout.
ProgressDeadlineExceededis a report, not an action.
| Example check | Evidence |
|---|---|
| Right template restored | Container image in .spec.template matches the chosen revision |
| Rollout finished | rollout status exits 0; UP-TO-DATE and AVAILABLE equal desired replicas |
| Strategy as intended | .spec.strategy.rollingUpdate shows the surge and unavailable values |
| No leftovers on the bad image | kubectl get pods -o wide and ReplicaSet counts show the bad ReplicaSet at 0 |
Cleanup: kubectl delete namespace prepium-tutorial. References: Deployments, kubectl rollout undo, kubectl rollout history. Next, try CKAD rollout verification or probes that gate a rollout.
Practice scope
This additional curriculum lab is available in single-task practice with the existing 12-minute limit. Its alternate scenario also appears in one of the two mixed curriculum mocks. The first three 17-task mocks keep their original task sets. Hints, an explained solution and requirement-by-requirement feedback are available in the lab.
Browse CKA practice tasks →