How a rolling update moves
The problem. Shipping a new version means replacing running pods. Done carelessly you get downtime (all old pods gone before new ones work) or a broken release everywhere in one minute. The rolling-update settings and the kubectl rollout commands let you ship safely and go back fast.
What you need to know already: Deployments, ReplicaSets and the basic rollout maths (15.16), readiness probes (17.20), annotations (15.26).
A Deployment's strategy decides how the old ReplicaSet is replaced by the new one:
spec:
replicas: 4
minReadySeconds: 10 # a new pod must stay Ready 10s before it counts as available
progressDeadlineSeconds: 600 # no progress for 10 min -> Progressing=False
strategy:
type: RollingUpdate # or Recreate: kill all old, then start new (downtime)
rollingUpdate:
maxSurge: 1 # at most replicas + 1 pods in total
maxUnavailable: 0 # never fewer than replicas available
- maxSurge: how many pods above
replicasmay exist during the update. Percentages round up (25% of 4 = 1). - maxUnavailable: how many below
replicasmay be unavailable. Percentages round down (25% of 4 = 1; 25% of 3 = 0). - Defaults: 25% / 25%. Both 0 is invalid.
maxSurge: 1, maxUnavailable: 0 is the zero-downtime setting: start one new pod, wait until it is available (Ready for minReadySeconds), remove one old, repeat. maxSurge: 0, maxUnavailable: 1 is the "no spare capacity" setting (quota-bound namespaces, anti-affinity per node): remove first, then add.
Readiness is what makes this safe. "Available" means Ready. A new version whose readiness probe never passes stalls the rollout with the old pods still serving:
# an illustration: shop/web with the strategy above (the rollout missions)
kubectl rollout status deploy/web -n shop --timeout=60s
Waiting for deployment "web" rollout to finish: 1 out of 4 new replicas have been updated...
error: timed out waiting for the condition
kubectl get pods -n shop -l app=web
NAME READY STATUS RESTARTS AGE
web-5d8f7c9b4d-2kq9x 1/1 Running 0 2d
web-5d8f7c9b4d-7mz4p 1/1 Running 0 2d
web-5d8f7c9b4d-q8w2x 1/1 Running 0 2d
web-5d8f7c9b4d-x9c2m 1/1 Running 0 2d
web-7c9f4d8b6c-4kq2x 0/1 Running 0 58s <- the new version, never Ready
Without a readiness probe the new pod is "available" the moment the process starts, and a broken release replaces every good pod in a minute.
After progressDeadlineSeconds without progress the Deployment says so:
# an illustration: shop/web with the strategy above (the rollout missions)
kubectl describe deploy web -n shop | grep -A3 Conditions
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing False ProgressDeadlineExceeded
kubectl rollout status deploy/web -n shop
error: deployment "web" exceeded its progress deadline
Kubernetes does not roll back automatically. ProgressDeadlineExceeded is a signal for your deployment automation (a script that runs kubectl rollout status and reacts to its exit code) or for you.
The rollout verbs
# an illustration: shop/web with the strategy above (the rollout missions)
kubectl rollout status deploy/web -n shop # block until done or failed (deploy scripts use this)
kubectl rollout history deploy/web -n shop
deployment.apps/web
REVISION CHANGE-CAUSE
1 <none>
2 bump to 1.28
3 bump to 1.29
kubectl rollout history deploy/web -n shop --revision=2 # the pod template of revision 2
kubectl rollout undo deploy/web -n shop # back to the previous revision
deployment.apps/web rolled back
kubectl rollout undo deploy/web -n shop --to-revision=1
kubectl rollout restart deploy/web -n shop # new pods, same spec (annotation bump)
kubectl rollout pause deploy/web -n shop # batch several changes...
kubectl rollout resume deploy/web -n shop # ...into one rollout
- Revisions are the ReplicaSets the Deployment keeps (
revisionHistoryLimit, default 10). Undo re-applies an old ReplicaSet's pod template; it becomes the newest revision (the old number disappears from the list). - CHANGE-CAUSE comes from the
kubernetes.io/change-causeannotation on the Deployment at the time of the change.--recordis deprecated; set it yourself:kubectl annotate deploy/web kubernetes.io/change-cause="bump to 1.29". - Undo does not undo everything: only the pod template. Replica count, strategy, and any ConfigMap the pods read are not part of a revision - rolling back the image does not roll back a config change you made in a ConfigMap.
- If your YAML lives in a Git repository and something re-applies it automatically, an undo in the cluster is only temporary: the next apply brings the bad version back. Revert the change in Git too.
Later (Ch 26): GitOps tools re-apply Git continuously, which makes "revert in Git" the only real rollback.
Recreate
strategy: {type: Recreate} scales the old ReplicaSet to 0, waits for its pods to be gone, then creates the new ones. Downtime by design. Used for workloads that must not run two versions at once (a singleton - a program that must only ever run once - holding a lock, an app with an incompatible database schema migration, an RWO volume that only one pod can mount, 16.41).
What you can now do
- Choose
maxSurge/maxUnavailablefor zero downtime, and explain why readiness makes it safe. - Use
rollout status,history,undo --to-revision,restart,pause/resume. - Record why a revision exists with the
kubernetes.io/change-causeannotation.