Deployment: updates and rollbacks
A Deployment is a manager of ReplicaSets. You get everything a ReplicaSet does, plus the thing it could not do: change the version of your app with no downtime, and go back if the new version is broken.
Deployment → ReplicaSet → Pod
Each version of your Pod template gets its own ReplicaSet. Updating means: scale the new ReplicaSet up, scale the old one down. Rolling back means doing the same in reverse.
The YAML
Look familiar? Change kind from ReplicaSet to Deployment and you have a working Deployment. The extra fields are optional.
apiVersion: apps/v1
kind: Deployment
metadata:
name: posts
spec:
replicas: 3
selector:
matchLabels:
app: posts
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
revisionHistoryLimit: 10
template:
metadata:
labels:
app: posts
spec:
containers:
- name: posts
image: micro-posts:v1
ports:
- containerPort: 4000
kind: Deployment
Same replicas, selector and template as a ReplicaSet. The Deployment creates a ReplicaSet from them for you; you never write the ReplicaSet yourself.
strategy
RollingUpdate (the default) replaces Pods a few at a time. maxSurge: 1 allows one Pod above replicas during the update; maxUnavailable: 0 forbids dropping below it. The other type, Recreate, kills all old Pods first, which means downtime.
revisionHistoryLimit
How many old ReplicaSets (scaled to 0) to keep for rollbacks. Default 10.
image
Changing anything in the template, usually the image tag, starts a rollout. Changing only replicas just scales; no new ReplicaSet.
Rolling update, live
Ship v2 and watch the two ReplicaSets trade Pods. Then ship the broken v3, see the rollout stop by itself, and roll back.
- At every moment at least 3 ready Pods serve traffic: no downtime.
- A new Pod must be ready before an old one is removed, so a broken release stalls instead of taking you down.
- Rollback reuses the old ReplicaSet: it is just another rolling update, backwards.
How fast it rolls
| Setting (replicas: 4) | What happens |
|---|---|
maxSurge: 1, maxUnavailable: 0 | Up to 5 Pods, never fewer than 4 ready. Safe, one at a time. |
Default: 25%, 25% | Up to 5 Pods, at least 3 ready. A bit faster. |
maxSurge: 0, maxUnavailable: 1 | Never more than 4 Pods (no spare capacity needed), but one fewer during the update. |
type: Recreate | All 4 old Pods stop, then 4 new start. Downtime; use only when two versions must never run together. |
The kubectl commands
$ kubectl apply -f deployment.yaml deployment.apps/posts created $ kubectl get deploy,rs,pods NAME READY UP-TO-DATE AVAILABLE deployment.apps/posts 3/3 3 3 NAME DESIRED CURRENT READY replicaset.apps/posts-7d9f8c6b5d 3 3 3 NAME READY STATUS pod/posts-7d9f8c6b5d-4kq2p 1/1 Running pod/posts-7d9f8c6b5d-m7x4t 1/1 Running pod/posts-7d9f8c6b5d-zt9wn 1/1 RunningOne file created three layers. Names chain:
posts→posts-7d9f8c6b5d→posts-7d9f8c6b5d-4kq2p. The hash identifies the Pod template.$ kubectl set image deployment/posts posts=micro-posts:v2 deployment.apps/posts image updated $ kubectl rollout status deployment/posts Waiting for deployment "posts" rollout to finish: 1 out of 3 new replicas have been updated... Waiting for deployment "posts" rollout to finish: 2 out of 3 new replicas have been updated... deployment "posts" successfully rolled outQuick way to change the image. The declarative way: edit the image in
deployment.yamlandkubectl applyagain.$ kubectl get rs NAME DESIRED CURRENT READY posts-7d9f8c6b5d 0 0 0 ← v1, kept posts-c4b21f7a9e 3 3 3 ← v2The old ReplicaSet stays at 0 for rollbacks.
$ kubectl rollout history deployment/posts REVISION CHANGE-CAUSE 1 <none> 2 <none>Every template change is a revision. Set the
kubernetes.io/change-causeannotation to fill in CHANGE-CAUSE.$ kubectl rollout undo deployment/posts deployment.apps/posts rolled back $ kubectl rollout undo deployment/posts --to-revision=1Back to the previous revision, or a specific one.
$ kubectl scale deployment/posts --replicas=5 deployment.apps/posts scaledScale the Deployment, never its ReplicaSet directly: the Deployment would just set it back.
$ kubectl delete deployment posts deployment.apps "posts" deletedDeletes its ReplicaSets and their Pods too.
Recap
- A Deployment manages ReplicaSets; each ReplicaSet manages Pods.
- Changing the Pod template creates a new ReplicaSet and rolls Pods over gradually.
maxSurgeandmaxUnavailablecontrol the pace and the safety margin.- Old ReplicaSets are kept at 0, so
kubectl rollout undois instant to start. - For stateless apps you write Deployments, not ReplicaSets or Pods.
Quick check
replicas: 3 to 5 and apply. Does that create a new ReplicaSet and a new revision?Show answer
No. Only changes to the Pod template create a new ReplicaSet. Changing replicas just scales the current one.
Show answer
With maxUnavailable: 0, an old Pod is removed only after a new one is ready. The v3 Pod never became ready, so all old Pods kept serving. In a real cluster, add a readiness probe (chapter 13) so that "ready" means the app actually answers, not just that the process started.
Deployments: common questions
What is the difference between a Deployment and a ReplicaSet?
A ReplicaSet keeps N Pods running. A Deployment manages ReplicaSets, creating a new one per version, which gives you rolling updates and rollbacks.