Deployments & ReplicaSets
A bare pod dies and stays dead. Production needs "keep three of these alive, always, and when I ship a new version, swap them out gradually with a way back." That's exactly what a Deployment is — and it's the object you'll actually write day to day.
💡 The Bottom Line
A Deployment declares "N replicas of this pod template." Under the hood it manages a ReplicaSet, whose only job is keeping exactly N matching pods alive. Change the template (a new image version) and the Deployment performs a rolling update — new ReplicaSet up, old one down, step by step — with one-command rollback.
The manifest
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: myapp:1.0
ports:
- containerPort: 3000
Notice the structure: everything under template: is just a pod manifest
(compare Lesson 2), embedded inside the Deployment. The selector tells the
Deployment which pods are "its" pods — it must match the template's labels. Labels doing real
work, as promised.
Self-healing, demonstrated
kubectl apply -f deployment.yaml
kubectl get pods # three pods, names like web-7f9b...-x2k4p
kubectl delete pod web-7f9b...-x2k4p
kubectl get pods # ...and there are three again, one brand new
You didn't restart anything — the ReplicaSet noticed actual (2) ≠ desired (3) and fixed it. This is the reconciliation loop from Lesson 1, now working for you.
Rolling updates and rollbacks
Edit the manifest's image to myapp:1.1 and re-apply — or imperatively:
kubectl set image deployment/web web=myapp:1.1
kubectl rollout status deployment/web # watch it happen
kubectl rollout history deployment/web
kubectl rollout undo deployment/web # bad release? one command back
The rollout replaces pods gradually — by default keeping the app available the whole time
(a few old pods keep serving until enough new ones are ready). A failed new version doesn't
take the site down, and undo returns to the previous ReplicaSet, which was never
deleted — just scaled to zero.
🙋 There Are No Dumb Questions
Q: Do I ever write a ReplicaSet myself?
A: Practically never. The Deployment creates and manages ReplicaSets for you — one per
version of your pod template — and uses them to orchestrate rollouts. You'll see
them in kubectl get rs output (that's where the hash in pod names comes from),
but you write Deployments. Same relationship as images and containers: one is the thing you
author, the other is machinery.
⚠️ Watch Out
A rolling update only helps if Kubernetes can tell a new pod is actually ready.
Without a readiness probe (a URL Kubernetes polls, e.g.
readinessProbe: httpGet: path: /healthz), a pod counts as ready the moment its
process starts — even if the app inside takes 20 more seconds to boot, meaning traffic hits
pods that can't answer yet. Add readiness probes to anything user-facing; it's the single
highest-value line in a production manifest.
🔧 Try It Yourself
Use a public image so there's nothing to build: set the image to
nginx:1.26 in the manifest above, apply it, then roll it forward and back:
kubectl set image deployment/web web=nginx:1.27
kubectl rollout status deployment/web
kubectl get rs # two ReplicaSets: new scaled up, old at 0
kubectl rollout undo deployment/web
Watch kubectl get pods -w in a second terminal during the rollout — you'll
see the old pods terminate one by one as new ones become ready.
✅ Quick Check
You delete one of a Deployment's three pods. What happens?
Next up: your pods are alive and healing — but their IPs change with every replacement. Services give that moving crowd one stable address.