flowchart LR D["Deployment web"] --> R1["ReplicaSet web-7c9d (rev 1)<br/>nginx:1.27 · 0 pods"] D --> R2["ReplicaSet web-6d8f (rev 2)<br/>nginx:1.28 · 3 pods"]
Deployment → ReplicaSet → Pod. Each change to the pod template (for example a new image) makes the Deployment create a new ReplicaSet (label pod-template-hash) and move pods over gradually. Old ReplicaSets are kept according to revisionHistoryLimit (default 10), so you can roll back at once without rerunning CI/CD.
Strategy
| Strategy | Behaviour |
|---|---|
RollingUpdate (default) |
Replaces pods gradually by maxSurge (how many extra pods) and maxUnavailable (how many missing pods). Both cannot be 0 |
Recreate |
Deletes every old pod before creating new ones — there is downtime |
Example replicas: 4, maxSurge: 1, maxUnavailable: 0: create 1 new pod, wait until Ready, then delete 1 old pod, so at least 4 pods always serve traffic.
Commands
kubectl create deployment web --image=nginx:1.27 --replicas=3
kubectl set image deployment/web nginx=nginx:1.28 # <container>=<image>
kubectl rollout status deployment/web
kubectl rollout history deployment/web
kubectl rollout undo deployment/web --to-revision=2
kubectl scale deployment web --replicas=5
kubectl autoscale deployment web --cpu-percent=50 --min=3 --max=10
Common traps:
set imageneeds the container name, not the Deployment name (withkubectl create deployment web --image=nginx:1.27, the container is callednginx).- The HPA shows
<unknown>if pods declare no CPU request or the cluster has no metrics-server. --recordis deprecated; record the reason with thekubernetes.io/change-causeannotation.
Rollouts in more detail
| Command | Use |
|---|---|
kubectl rollout pause deployment/web |
Make several changes without triggering a rollout for each |
kubectl rollout resume deployment/web |
Start one rollout with all changes |
kubectl rollout restart deployment/web |
Recreate pods with the same template, for example to reload a ConfigMap |
kubectl annotate deployment/web kubernetes.io/change-cause="upgrade to 1.28" |
Record why, shown in history |
progressDeadlineSeconds (600 by default) marks a rollout as failed if new pods do not become ready in time; kubectl rollout status then exits with an error, which a CI pipeline can catch. minReadySeconds makes a pod wait a little after becoming Ready before it counts as available, catching apps that crash shortly after start.
Readiness makes rollouts safe
A rolling update only moves forward when new pods pass their readiness probe. Without one, Kubernetes considers a pod ready as soon as the container starts, so a broken version can replace every healthy pod. Readiness probes plus maxUnavailable: 0 give zero-downtime updates.
Protecting availability
A PodDisruptionBudget limits voluntary disruptions such as node drains:
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata: { name: web-pdb }
spec:
minAvailable: 2
selector: { matchLabels: { app: web } }
Advanced release strategies
| Strategy | Idea | How in Kubernetes |
|---|---|---|
| Blue/green | Run the new version fully, then switch all traffic | Two Deployments, change the Service selector |
| Canary | Send a small share of traffic to the new version first | Two Deployments behind one Service, or an ingress or mesh that splits by weight |
| Progressive delivery | Automate canary steps with metric checks | Tools such as Argo Rollouts or Flagger |
Autoscaling notes
The HPA (autoscaling/v2) can scale on CPU, memory, or custom metrics, with a behavior section to slow down scale-in. It changes replicas itself, so do not also hard-code replicas in a file that is reapplied by CI, or the two will fight.