KubernetesXV · DeploymentsDeployments
Rolling updates — maxSurge, maxUnavailable, and rollout phases
What you'll learn
- Trace the rollout phases (scaling new RS up, scaling old RS down)
- Configure maxSurge and maxUnavailable for the workload
- Reason about the trade-offs (capacity vs availability)
- Diagnose stuck rollouts
Prerequisites
Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16
Rolling updates are the standard Deployments rollout
strategy. This lesson explains the rollout phases, the
meaning of maxSurge and maxUnavailable, and how to tune
them for the workload.
The rollout phases
sequenceDiagram
participant D as Deployment
participant New as New ReplicaSet
participant Old as Old ReplicaSet
Note over D,Old: Initial: Old RS = 3 Pods
D->>New: create new RS (0 Pods)
D->>New: scale to 1 (maxSurge allows)
D->>Old: scale to 2 (maxUnavailable allows)
D->>New: scale to 2
D->>Old: scale to 1
D->>New: scale to 3
D->>Old: scale to 0
Note over D,Old: Final: New RS = 3 Pods
The phases:
- Create new ReplicaSet: the Deployment creates the new RS at 0 replicas.
- Scale up new: incrementally scale up the new RS,
respecting
maxSurge. - Scale down old: incrementally scale down the old RS,
respecting
maxUnavailable. - Final state: new RS at desired replicas; old RS at 0 (but retained for revision history).
The total number of Pods oscillates between
replicas - maxUnavailable and replicas + maxSurge
during the rollout.
maxSurge and maxUnavailable
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
Both can be a number or a percentage of replicas.
maxSurge: how many Pods can exist above the desired
replicas during the rollout.
maxSurge: 25%of 3 replicas = max surge of 1 Pod.maxSurge: 0: no surge allowed (every new Pod requires an old Pod to be removed first).maxSurge: 100%: double the replicas during the rollout (every old Pod has a replacement before removal).
maxUnavailable: how many Pods can be unavailable
during the rollout.
maxUnavailable: 25%of 3 replicas = max unavailable of 1.maxUnavailable: 0: no unavailable allowed (every old Pod must have a replacement before being removed).maxUnavailable: 100%: all old Pods can be removed at once (the cluster temporarily serves fewer Pods).
Tuning maxSurge and maxUnavailable
The trade-offs:
| Setting | Capacity impact | Availability impact |
|---|---|---|
maxSurge: 25%, maxUnavailable: 25% | Up to 25% extra capacity during rollout | Up to 25% unavailable |
maxSurge: 100%, maxUnavailable: 0% | Up to 100% extra capacity | Zero unavailability |
maxSurge: 0%, maxUnavailable: 100% | No extra capacity | Up to 100% unavailable |
maxSurge: 25%, maxUnavailable: 0% | Up to 25% extra capacity | Zero unavailability |
For a service that must not lose capacity during rollouts:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 25% # extra capacity during rollout
maxUnavailable: 0% # never fewer Pods than desired
This requires the cluster to have spare capacity for the surge.
For a service that can tolerate temporary unavailability:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 0%
maxUnavailable: 25%
No extra capacity needed; some Pods are unavailable during the rollout.
How the rollout proceeds
For 3 replicas, maxSurge: 25%, maxUnavailable: 25%:
gantt
title Rolling update (3 replicas, maxSurge 25%, maxUnavailable 25%)
dateFormat X
axisFormat %s
section Old RS
Old RS :a1, 0, 5s
Old RS :a2, 5, 5s
Old RS :a3, 10, 5s
Old RS :a4, 15, 5s
Old RS :a5, 20, 5s
Old RS :a6, 25, 5s
Old RS :a7, 30, 5s
Old RS :a8, 35, 5s
Old RS :a9, 40, 5s
section New RS
New RS :b1, 0, 5s
New RS :b2, 5, 10s
New RS :b3, 15, 5s
New RS :b4, 25, 5s
New RS :b5, 35, 5s
New RS :b6, 45, 5s
At each step:
- Step 1: Old=3, New=0, Total=3. (Old=3)
- Step 2: Old=3, New=1, Total=4. (Surge 1)
- Step 3: Old=2, New=1, Total=3. (Unavailable 1)
- Step 4: Old=2, New=2, Total=4. (Surge 1)
- Step 5: Old=1, New=2, Total=3. (Unavailable 1)
- Step 6: Old=1, New=3, Total=4. (Surge 1)
- Step 7: Old=0, New=3, Total=3. (Unavailable 1)
The total oscillates between 3 and 4; old count decreases while new increases.
Why Deployments pause rollouts
During the rollout, the Deployment waits for the new Pods to become Ready before scaling down old Pods further. If the new Pod fails readiness, the rollout stalls.
flowchart LR
Create[Create new Pod] --> Ready{Ready?}
Ready -- yes --> Next[Scale down old]
Ready -- no --> Wait[Wait for Ready]
Wait --> Timeout{Reached<br/>progress deadline?}
Timeout -- no --> Ready
Timeout -- yes --> Fail[Mark rollout failed]
The progressDeadlineSeconds (default 600s) controls how
long the Deployment waits before marking the rollout as
failed.
Production discipline: set progressDeadlineSeconds
deliberately. A short deadline (60s) fails fast; a long
deadline (1800s) tolerates slow rollouts.
Diagnosing stuck rollouts
A rollout that won’t progress:
kubectl rollout status deployment/web --timeout=60s
# error: deployment "web" exceeded its progress deadline
Common causes:
- New Pod fails readiness probe: check the readiness probe configuration.
- New Pod cannot start: ImagePullBackOff, runtime error.
- Insufficient capacity: cluster cannot fit the surge.
- PDB blocking: PodDisruptionBudget prevents scaling down old Pods.
# Check Pod status
kubectl get pods -l app=web
# Check events
kubectl describe deployment/web | tail -30
# Check PDB
kubectl get pdb -n team-a-prod
Production patterns
High-availability HTTP service:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 25%
maxUnavailable: 0% # never lose capacity
maxUnavailable: 0% ensures the cluster always has the
desired number of Pods. The trade-off: cluster needs surge
capacity.
Resource-constrained batch worker:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 0%
maxUnavailable: 50%
maxSurge: 0% means no extra capacity; maxUnavailable: 50%
means up to half the Pods can be down during rollout.
Suitable for batch workers where temporary unavailability is
tolerable.
Fast rollout for low-replica services:
spec:
replicas: 2
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
With 2 replicas and maxSurge: 1, maxUnavailable: 0, the
rollout adds 1 new Pod, waits for it to be Ready, then
removes 1 old Pod.
Cross-course references
- The Linux course part
XXXVII-Linux-Resourcescovers process restart patterns; rolling updates are the cluster-level equivalent. - The Ansible course part
XXXV-Ansible-Scriptingcovers rolling restarts; kubectl rollout is the cluster-level equivalent. - The Docker course part
XXXIV-Docker-Productioncovers blue-green deploys; rolling updates are a simpler alternative.
Quiz
Knowledge check · 4 questions
Q1. A Deployment has `maxSurge: 0%` and `maxUnavailable: 0%`. What happens?
Q2. `maxSurge: 25%` requires the cluster to have 25% extra capacity during the rollout.
Q3. A Deployment's rollout stalls at `Progressing=False`. New Pods are in `Pending`. The cluster has spare capacity on most nodes but the surge Pod is pending on a specific node pool. Diagnose.
Deployment `web` with 5 replicas, `maxSurge: 25%, maxUnavailable: 25%`. Rollout started; 1 new Pod created; the rollout stalled. The new Pod is Pending with `nodeAffinity` not satisfied. The cluster has 10 nodes, 8 with spare capacity. 2 nodes have no spare capacity.
Q4. When is `maxSurge: 0%, maxUnavailable: 25%` the right choice for a Deployment?
Passing score: 75%. Answers are checked in this browser.
Production discipline
- Configure
maxSurgeandmaxUnavailabledeliberately. Default is 25% / 25%; tune based on the workload’s tolerance. - Ensure surge capacity before rolling out. Monitor cluster utilisation; pre-scale if needed.
- Avoid
maxSurge: 0%, maxUnavailable: 0%. This deadlocks the rollout. - Set
progressDeadlineSecondsdeliberately. Default 600s; tune based on the rollout’s expected duration. - Test rollouts in staging first. Verify the
maxSurge/maxUnavailablesettings match the cluster’s capacity.