Kubernetes rolling update simulator
Change a Deployment’s image and Kubernetes replaces its pods a few at a time. This simulator follows the deployment controller’s own scaling rules, so you can see exactly what maxSurge and maxUnavailable allow, how long each step waits for readiness, why a rollout gets stuck and what Recreate does instead. Below it: how the controller decides each step, and how to roll out safely.
- 0 sScaled up replica set web-5f8c6a to 2
- 0 sScaled down replica set web-7d4b9c to 5
- 0 sScaled up replica set web-5f8c6a to 3
- 6 sScaled down replica set web-7d4b9c to 2
- 6 sScaled up replica set web-5f8c6a to 6
- 12 sScaled down replica set web-7d4b9c to 0
- 12 sdeployment "web" successfully rolled out
- maxSurge 25% of 6
- 2 pods (rounded up)
- maxUnavailable 25% of 6
- 1 pod (rounded down)
- Pods allowed (not counting terminating)
- 8
- Most pods running
- 8, 11 with terminating
- Fewest available
- 5
How to use the simulator
The Deployment starts with all replicas on version v1, and at time 0 its image is changed to v2. The simulator runs the rollout to the end and shows the pods at any moment (drag the slider or press Play), the number of pods in each state over time, and the events the deployment controller records, worded as kubectl describe deployment shows them.
Things to try:
- With 10 replicas, compare maxSurge 1, maxUnavailable 0 (never below full capacity) with maxSurge 0, maxUnavailable 1 (never above it).
- Set maxSurge to 100% and maxUnavailable to 0: a full set of new pods comes up beside the old ones, close to a blue-green switch.
- Choose Never becomes ready: the rollout stops, and the old version keeps serving.
- Set both to 0 to see the validation error, and try Recreate to see the gap with no pods.
What is a rolling update?
A rolling update replaces the pods of an application with pods of a new version gradually, so that the application keeps serving traffic throughout. In Kubernetes it is the default way a Deployment changes version: edit the pod template (usually the image tag) and the deployment controller takes it from there.
A Deployment does not manage pods directly. It owns ReplicaSets, one per version of the pod template, and each ReplicaSet keeps a given number of identical pods running. A rollout creates a ReplicaSet for the new template and shifts replicas from the old one to the new one, while the ReplicaSet controller creates and deletes the actual pods. The old ReplicaSet is kept at zero replicas afterwards, which is what makes kubectl rollout undo possible.
How the controller decides each step
Every time something changes, the deployment controller runs the same two checks, in pkg/controller/deployment/rolling.go:
- Scale up the new ReplicaSet if the total of all ReplicaSets’ replicas is below replicas + maxSurge, by the difference, but never above replicas.
- If it did not scale up, scale down old ReplicaSets, but only as far as availability allows. It first removes old pods that are not available anyway, then removes available old pods until the number of available pods across all ReplicaSets would drop below replicas − maxUnavailable. New pods that are not available yet are counted against the budget, so unhealthy new pods cannot cause old ones to be removed.
Each scale-up therefore waits for room under the surge limit, and each scale-down waits for new pods to become available. The Kubernetes documentation shows the events for a 3-replica Deployment with the defaults; the simulator, set to 3 replicas, produces the same sequence:
0 s Scaled up replica set web-5f8c6a to 1
6 s Scaled down replica set web-7d4b9c to 2
6 s Scaled up replica set web-5f8c6a to 2
12 s Scaled down replica set web-7d4b9c to 1
12 s Scaled up replica set web-5f8c6a to 3
18 s Scaled down replica set web-7d4b9c to 0
18 s deployment "web" successfully rolled out With 3 replicas, maxSurge 25% resolves to 1 and maxUnavailable 25% to 0, so the rollout proceeds one pod at a time: one new pod comes up, and only when it is available does an old one go.
maxSurge and maxUnavailable
maxSurge limits how many pods may exist above the desired count; maxUnavailable limits how many of the desired pods may be unavailable. Each is a number or a percentage of replicas, and both default to 25%. A percentage is rounded up for maxSurge and down for maxUnavailable, so small Deployments get at least one extra pod and never lose capacity by rounding. Both cannot be zero, since the rollout could then never start; if rounding makes both zero, the controller uses maxUnavailable 1. For the defaults:
| Replicas | maxSurge 25% | maxUnavailable 25% | Pods during rollout | Available at least |
|---|---|---|---|---|
| 1 | 1 | 0 | up to 2 | 1 |
| 2 | 1 | 0 | up to 3 | 2 |
| 3 | 1 | 0 | up to 4 | 3 |
| 4 | 1 | 1 | up to 5 | 3 |
| 5 | 2 | 1 | up to 7 | 4 |
| 6 | 2 | 1 | up to 8 | 5 |
| 8 | 2 | 2 | up to 10 | 6 |
| 10 | 3 | 2 | up to 13 | 8 |
| 20 | 5 | 5 | up to 25 | 15 |
The two settings trade speed against spare capacity and safety. The same 10-replica rollout in the simulator:
| Settings | Duration | Fewest available | Most pods (with terminating) |
|---|---|---|---|
| maxSurge 25%, maxUnavailable 25% (default) | 12 s | 8 | 13 (18) |
| maxSurge 1, maxUnavailable 0 | 60 s | 10 | 11 (12) |
| maxSurge 0, maxUnavailable 1 | 60 s | 9 | 10 (11) |
| maxSurge 100%, maxUnavailable 0 | 6 s | 10 | 20 (20) |
| Recreate | 11 s | 0 | 10 (10) |
A surge needs spare room in the cluster (and in any ResourceQuota) for the extra pods; a non-zero maxUnavailable needs spare capacity in the application, because fewer pods carry the full load. Terminating pods are not counted in either limit, so for a while the cluster runs more pods than replicas plus maxSurge, as the last column shows.
Readiness and minReadySeconds
A rolling update is only as safe as the signal that a new pod works. A pod counts as ready when its containers are running and its readiness probe passes; only ready pods receive traffic from Services. It counts as available once it has been ready for minReadySeconds (0 by default). The controller scales the old version down only as new pods become available, so a readiness probe that checks real dependencies, and a minReadySeconds long enough to catch pods that crash soon after starting, are what stop a bad version from replacing a good one.
Without a readiness probe, a pod is ready as soon as its containers start, before the application may be listening, and a rollout can replace every pod with a broken one.
Stuck rollouts and rollbacks
If new pods never become available, because the image does not exist, the container crashes, or the readiness probe never passes, the rollout stops: the controller has already scaled the old ReplicaSet down by maxUnavailable and will go no further. The application keeps running on the remaining old pods. After progressDeadlineSeconds (600 by default) without progress, the Deployment’s Progressing condition becomes false with reason ProgressDeadlineExceeded, and kubectl rollout status exits with an error. Kubernetes does not roll back automatically; CI pipelines usually watch for that status and run kubectl rollout undo, which scales the previous ReplicaSet back up with the same rolling rules.
Shutting pods down cleanly
A zero-downtime rollout also needs old pods to stop gracefully. When a pod is deleted, Kubernetes marks it terminating, removes it from Service endpoints, runs any preStop hook, and sends SIGTERM to its containers. It waits up to terminationGracePeriodSeconds (30 by default) and then sends SIGKILL. Endpoint removal happens in parallel with SIGTERM, so for a short time load balancers and kube-proxy may still send new requests to a pod that is shutting down. Applications should keep serving for a few seconds after SIGTERM (a short preStop sleep is a common way), finish in-flight requests, and then exit.
A PodDisruptionBudget limits voluntary evictions, such as node drains, rather than rollouts; the Deployment’s own maxUnavailable governs rollouts.
Recreate, blue-green and canary
The Recreate strategy scales the old ReplicaSet to zero, waits for its pods to terminate, and only then creates the new pods. There is downtime, but two versions never run at the same time, which matters when they cannot share a database schema or a lock.
A rolling update sends traffic to old and new pods at once, in proportion to their numbers, and cannot pause on its own to check metrics. Teams that need more control use blue-green deployments (bring up a full new set, then switch the Service selector) or canary releases (send a small share of traffic to the new version, watch error rates, then increase). Argo Rollouts and Flagger automate both on Kubernetes, with automatic rollback on failing metrics. kubectl rollout pause and resume give a manual version of the same idea.
In interviews
Platform and SRE interviews ask how Kubernetes rolls out a new version without downtime. A good answer covers Deployments and ReplicaSets, the meaning and rounding of maxSurge and maxUnavailable, readiness probes as the gate for each step, graceful termination with SIGTERM and the endpoint removal race, what happens when the new version is broken, and how to roll back. Follow-ups often ask when you would choose Recreate, blue-green or canary instead, and how database migrations fit in: make schema changes backward compatible so that old and new versions can run side by side during the rollout.
Rolling update questions and answers
How does a Kubernetes rolling update work?
When you change a Deployment’s pod template, the deployment controller creates a new ReplicaSet for the new version and moves replicas from the old ReplicaSet to the new one in steps. It scales the new ReplicaSet up as far as maxSurge allows, waits for new pods to become available, then scales the old ReplicaSet down as far as maxUnavailable allows, and repeats until every replica runs the new version.
What are maxSurge and maxUnavailable?
maxSurge is how many pods above the desired replica count may exist during a rollout; maxUnavailable is how many of the desired replicas may be unavailable. Both accept a number or a percentage of replicas and default to 25%. Percentages are rounded up for maxSurge and down for maxUnavailable, and they cannot both be zero.
Why is my Kubernetes rollout stuck?
Usually because the new pods never become ready: the image cannot be pulled, the container crashes, or the readiness probe fails. The controller will not scale the old ReplicaSet down further than maxUnavailable allows, so the rollout waits. After progressDeadlineSeconds (600 by default) without progress, the Deployment reports ProgressDeadlineExceeded, but Kubernetes does not roll back by itself; use kubectl rollout undo or fix the new version.
What is the difference between RollingUpdate and Recreate?
RollingUpdate replaces pods gradually, keeping at least replicas minus maxUnavailable available, so old and new versions run side by side for a while. Recreate deletes all old pods first and creates the new ones only after they are gone, which causes downtime but guarantees two versions never run at once, which some applications need, for example when they cannot share a database schema.
What does minReadySeconds do?
It is how long a new pod must stay ready, without any container crashing, before it counts as available. The default is 0. A higher value slows the rollout down but catches pods that pass their readiness probe and then crash shortly after.
How do I roll back a Deployment?
Run kubectl rollout undo deployment/name, or kubectl rollout undo deployment/name --to-revision=N. The Deployment keeps old ReplicaSets, scaled to zero, as its revision history (revisionHistoryLimit, 10 by default), and rolling back scales an old ReplicaSet up again using the same rolling update rules.
Why are there more pods than replicas plus maxSurge during a rollout?
Because terminating pods are not counted. When the controller scales the old ReplicaSet down, its pods start terminating and get up to terminationGracePeriodSeconds (30 by default) to shut down, while the controller already creates new pods in their place. For a while the cluster runs more pods than replicas plus maxSurge, which matters for resource quotas and node capacity.
Further reading
- Kubernetes documentationDeploymentsRolling updates, rollbacks, maxSurge, maxUnavailable and progress deadlines.
- Kubernetes sourcepkg/controller/deployment/rolling.goThe scale-up and scale-down rules this simulator follows, with comments.
- Kubernetes documentationTermination of PodsSIGTERM, grace periods and preStop hooks.
- Argo projectArgo RolloutsBlue-green and canary deployments with metric analysis.
- SemicolonyHow a pod gets createdWhat happens between kubectl apply and a running container.