13: Update Strategies
13: Update Strategies
Objective
Learn the two Deployment update strategies in Kubernetes — Recreate and RollingUpdate — and understand how to control the rollout behavior using maxSurge and maxUnavailable. Practice updating Deployments and using rollout commands.
Theory
Update Strategies
When you change the Pod template in a Deployment (e.g., update the container image), Kubernetes needs to replace the old Pods with new ones. The strategy field controls how this replacement happens.
| Strategy | Behavior | Downtime |
|---|---|---|
| Recreate | Terminates all existing Pods before creating new ones | Yes — all Pods are down between termination and creation |
| RollingUpdate | Gradually replaces old Pods with new ones | No — traffic is served throughout the rollout (if configured correctly) |
Recreate vs RollingUpdate
graph TB
subgraph RecreateStrategy["Recreate Strategy"]
direction TB
R1["3 Pods v1 running"] --> R2["All 3 Pods v1 terminated"]
R2 --> R3["DOWNTIME"]
R3 --> R4["3 Pods v2 starting"]
R4 --> R5["3 Pods v2 running"]
end
subgraph RollingStrategy["RollingUpdate Strategy"]
direction TB
U1["3 Pods v1 running"] --> U2["1 Pod v2 created<br/>3 Pods v1 still running"]
U2 --> U3["1 Pod v1 terminated<br/>1 Pod v2 ready"]
U3 --> U4["2nd Pod v2 created<br/>2 Pods v1 still running"]
U4 --> U5["Continues until<br/>3 Pods v2 running"]
end
style R3 fill:#ffcdd2,stroke:#c62828,stroke-width:2px
style U1 fill:#c8e6c9,stroke:#2e7d32,stroke-width:1px
style U5 fill:#c8e6c9,stroke:#2e7d32,stroke-width:1px
style R1 fill:#c8e6c9,stroke:#2e7d32,stroke-width:1px
style R5 fill:#c8e6c9,stroke:#2e7d32,stroke-width:1px
maxSurge and maxUnavailable
For the RollingUpdate strategy, two parameters control the speed and safety of the rollout:
| Parameter | Description | Default |
|---|---|---|
maxSurge |
Maximum number of Pods that can be created above the desired replica count during the update | 25% |
maxUnavailable |
Maximum number of Pods that can be unavailable during the update | 25% |
Both values can be an absolute number or a percentage of the desired replicas.
maxSurge and maxUnavailable Examples
For a Deployment with 3 replicas:
| maxSurge | maxUnavailable | Total Pods During Update | Min Available | Behavior |
|---|---|---|---|---|
1 |
0 |
Up to 4 (3 + 1) | 3 (all must be available) | Safest — no Pod is removed until the new one is ready |
0 |
1 |
Up to 3 | 2 (1 can be down) | No extra capacity — removes 1 old Pod before creating a new one |
1 |
1 |
Up to 4 | 2 | Balanced — faster than the safest option |
2 |
1 |
Up to 5 | 2 | Fast — creates 2 extra Pods at once, allows 1 down |
100% |
0 |
Up to 6 (3 + 3) | 3 | Blue-green style — all new Pods created before old ones removed |
When to Use Each Strategy
| Use Case | Recommended Strategy |
|---|---|
| Application cannot run multiple versions simultaneously | Recreate |
| Database schema migrations that require exclusive access | Recreate |
| Zero-downtime web services | RollingUpdate (maxSurge=1, maxUnavailable=0) |
| Fast rollout where brief capacity reduction is acceptable | RollingUpdate (maxSurge=2, maxUnavailable=1) |
Practical Tasks
Task 1: Recreate Strategy
Deploy kuard v1 with 3 replicas using the Recreate strategy, then update to v2 and observe all Pods terminating before new ones start.
Create a file called deployment-recreate.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: kuard-recreate
namespace: student-XX
labels:
app: kuard-recreate
spec:
replicas: 3
strategy:
type: Recreate
selector:
matchLabels:
app: kuard-recreate
template:
metadata:
labels:
app: kuard-recreate
spec:
containers:
- name: kuard
image: <ACR_NAME>.azurecr.io/kuard:1
ports:
- containerPort: 8080
resources:
requests:
cpu: "100m"
memory: "64Mi"
limits:
cpu: "100m"
memory: "64Mi"
Deploy and wait for all 3 Pods to be running:
kubectl apply -f deployment-recreate.yaml
kubectl get pods -n student-XX -l app=kuard-recreate -w
Once all 3 Pods are running, open a second terminal and start watching:
kubectl get pods -n student-XX -l app=kuard-recreate -w
In the first terminal, update the image to kuard:2:
kubectl set image deployment/kuard-recreate kuard=<ACR_NAME>.azurecr.io/kuard:2 -n student-XX
In the watch terminal, observe the behavior:
NAME READY STATUS RESTARTS AGE
kuard-recreate-6b8c9d7f6-abc12 1/1 Terminating 0 2m
kuard-recreate-6b8c9d7f6-def34 1/1 Terminating 0 2m
kuard-recreate-6b8c9d7f6-ghi56 1/1 Terminating 0 2m
kuard-recreate-6b8c9d7f6-abc12 0/1 Terminating 0 2m
kuard-recreate-6b8c9d7f6-def34 0/1 Terminating 0 2m
kuard-recreate-6b8c9d7f6-ghi56 0/1 Terminating 0 2m
kuard-recreate-8f4a2e1b3-jkl78 0/1 Pending 0 0s
kuard-recreate-8f4a2e1b3-mno90 0/1 Pending 0 0s
kuard-recreate-8f4a2e1b3-pqr12 0/1 Pending 0 0s
kuard-recreate-8f4a2e1b3-jkl78 1/1 Running 0 5s
kuard-recreate-8f4a2e1b3-mno90 1/1 Running 0 5s
kuard-recreate-8f4a2e1b3-pqr12 1/1 Running 0 5s
Notice that all old Pods are terminated before any new Pods are created. There is a period of complete downtime.
Task 2: Safe RollingUpdate (maxSurge=1, maxUnavailable=0)
Deploy kuard v2 with the safest rolling update configuration — no Pod is removed until the replacement is ready.
Create a file called deployment-rolling-safe.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: kuard-rolling-safe
namespace: student-XX
labels:
app: kuard-rolling-safe
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app: kuard-rolling-safe
template:
metadata:
labels:
app: kuard-rolling-safe
spec:
containers:
- name: kuard
image: <ACR_NAME>.azurecr.io/kuard:2
ports:
- containerPort: 8080
resources:
requests:
cpu: "100m"
memory: "64Mi"
limits:
cpu: "100m"
memory: "64Mi"
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
Deploy and wait for all 3 Pods to be running:
kubectl apply -f deployment-rolling-safe.yaml
kubectl rollout status deployment/kuard-rolling-safe -n student-XX
Start watching in a second terminal:
kubectl get pods -n student-XX -l app=kuard-rolling-safe -w
Trigger the rolling update by changing the image to kuard:3:
kubectl set image deployment/kuard-rolling-safe kuard=<ACR_NAME>.azurecr.io/kuard:3 -n student-XX
Observe the gradual replacement. With maxUnavailable: 0, you should always see at least 3 ready Pods during the rollout:
NAME READY STATUS RESTARTS AGE
kuard-rolling-safe-6b8c9d7f6-abc12 1/1 Running 0 2m
kuard-rolling-safe-6b8c9d7f6-def34 1/1 Running 0 2m
kuard-rolling-safe-6b8c9d7f6-ghi56 1/1 Running 0 2m
kuard-rolling-safe-8f4a2e1b3-jkl78 0/1 ContainerCreating 0 1s
kuard-rolling-safe-8f4a2e1b3-jkl78 1/1 Running 0 5s
kuard-rolling-safe-6b8c9d7f6-abc12 1/1 Terminating 0 2m
Check the rollout status:
kubectl rollout status deployment/kuard-rolling-safe -n student-XX
deployment "kuard-rolling-safe" successfully rolled out
Task 3: Fast RollingUpdate (maxSurge=2, maxUnavailable=1)
Deploy a faster rolling update configuration that trades some safety for speed.
Create a file called deployment-rolling-fast.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: kuard-rolling-fast
namespace: student-XX
labels:
app: kuard-rolling-fast
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 2
maxUnavailable: 1
selector:
matchLabels:
app: kuard-rolling-fast
template:
metadata:
labels:
app: kuard-rolling-fast
spec:
containers:
- name: kuard
image: <ACR_NAME>.azurecr.io/kuard:2
ports:
- containerPort: 8080
resources:
requests:
cpu: "100m"
memory: "64Mi"
limits:
cpu: "100m"
memory: "64Mi"
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
Deploy and wait for all Pods to be running:
kubectl apply -f deployment-rolling-fast.yaml
kubectl rollout status deployment/kuard-rolling-fast -n student-XX
Start watching and trigger the update:
kubectl get pods -n student-XX -l app=kuard-rolling-fast -w
kubectl set image deployment/kuard-rolling-fast kuard=<ACR_NAME>.azurecr.io/kuard:3 -n student-XX
With maxSurge: 2 and maxUnavailable: 1, you may see up to 5 Pods total (3 + 2) and as few as 2 available at once. The rollout completes faster because multiple Pods are replaced simultaneously.
Compare the rollout speed with the safe strategy from Task 2.
Clean Up
kubectl delete deployment kuard-recreate kuard-rolling-safe kuard-rolling-fast -n student-XX
Useful Commands
| Command | Description |
|---|---|
kubectl rollout status deployment <name> -n student-XX |
Watch the progress of a rollout |
kubectl rollout history deployment <name> -n student-XX |
View the revision history of a Deployment |
kubectl rollout undo deployment <name> -n student-XX |
Roll back to the previous revision |
kubectl rollout undo deployment <name> --to-revision=N -n student-XX |
Roll back to a specific revision |
kubectl rollout pause deployment <name> -n student-XX |
Pause a rollout (useful for canary-style testing) |
kubectl rollout resume deployment <name> -n student-XX |
Resume a paused rollout |
kubectl set image deployment <name> <container>=<image> -n student-XX |
Update the image of a Deployment |
Common Problems
| Problem | Possible Cause | Solution |
|---|---|---|
| Rollout stuck, new Pods not becoming ready | Readiness probe failing on new Pods | Check logs and describe the new Pods; fix the issue or rollback |
| Old Pods not terminating | maxUnavailable: 0 and new Pods never become ready |
Check readiness probe; the rollout waits for new Pods to be ready before removing old ones |
| All Pods down after update with Recreate | Expected behavior for Recreate strategy | Use RollingUpdate for zero-downtime deployments |
kubectl rollout undo has no effect |
Only one revision in history | Check kubectl rollout history — you need at least 2 revisions to undo |
| Rollout too slow | Conservative maxSurge/maxUnavailable settings | Increase maxSurge or maxUnavailable for faster rollouts |
Best Practices
- Use RollingUpdate for production workloads — Recreate causes downtime and should only be used when the application cannot tolerate running multiple versions simultaneously.
- Start with maxSurge=1, maxUnavailable=0 — This is the safest configuration. Only relax these settings when you need faster rollouts and can tolerate brief capacity reduction.
- Always configure readiness probes — Without readiness probes, Kubernetes considers a Pod ready as soon as the container starts. This can route traffic to Pods that are not yet fully initialized.
- Record the cause of changes — Use
kubectl apply -fwith version-controlled YAML files so you have a history of changes in your source control. - Test rollbacks — Regularly practice
kubectl rollout undoso you are prepared for production incidents. - Use
kubectl rollout pausefor canary testing — Pause a rollout after the first new Pod is ready, verify it works correctly, then resume.
Summary
In this exercise you learned:
- The difference between Recreate (downtime) and RollingUpdate (zero-downtime) strategies
- How maxSurge controls the number of extra Pods created during a rollout
- How maxUnavailable controls the minimum number of available Pods during a rollout
- How to observe rollout behavior in real time with
kubectl get pods -w - How to use rollout commands: status, history, undo, pause, and resume
- The trade-off between rollout safety (maxSurge=1, maxUnavailable=0) and speed (higher values)