Chapter 55 — Pods, Deployments, and ReplicaSets
In one sentence
A Pod is the smallest deployable unit (one or more tightly-coupled containers sharing a network namespace), a ReplicaSet keeps a specified NUMBER of identical pods running, and a Deployment manages ReplicaSets over time — enabling safe, versioned rollouts and rollbacks.
Why this matters
You will write, read, and debug Deployment manifests constantly in any real
Kubernetes role — understanding the three-layer relationship (Deployment
manages ReplicaSets manages Pods) explains a huge amount of kubectl
output that otherwise looks redundant or confusing.
How it actually works
# a minimal, real Deployment manifest
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
replicas: 3 # I want THREE identical pods
selector:
matchLabels:
app: web-app
template: # the POD TEMPLATE -- what each
# replica actually looks like
metadata:
labels:
app: web-app
spec:
containers:
- name: web
image: nginx:1.25
ports:
- containerPort: 80
THE THREE LAYERS, and why each exists:
POD one or more containers that share a network namespace
(Chapter 44) and are always scheduled TOGETHER, on the
SAME node. Pods are treated as EPHEMERAL and DISPOSABLE
-- you almost never create one directly in real use;
you describe what you want at the Deployment level and
let Kubernetes create/destroy Pods as needed.
REPLICASET ensures a SPECIFIED NUMBER of pods matching a
selector are running, AT ALL TIMES -- if one crashes or
is deleted, the ReplicaSet's controller (Chapter 54)
notices and creates a replacement.
DEPLOYMENT manages ReplicaSets OVER TIME, enabling ROLLING
UPDATES (Chapter 60): when you change the pod template
(a new image version, say), the Deployment creates a
NEW ReplicaSet with the new template, gradually scales
it UP while scaling the OLD ReplicaSet DOWN, and keeps
the old ReplicaSet around (scaled to zero) so a ROLLBACK
is fast if needed.
kubectl apply -f deployment.yaml # create or UPDATE, declaratively
kubectl get deployments
kubectl get replicasets # you'll see one per version
# you've ever deployed (kept
# around, scaled to 0, for
# rollback -- up to a
# configurable history limit)
kubectl get pods # the actual, currently
# running containers
kubectl scale deployment web-app --replicas=5 # imperatively change
# the desired count
Real-world example
Niantic's Pokemon GO launch in July 2016 is a well-documented, real,
dramatic case study in why AUTOMATIC, RELIABLE SCALING (exactly what
Deployments and ReplicaSets provide the foundation for) matters:
Google Cloud published its own technical account of the event,
describing that actual player demand reached roughly FIFTY TIMES
Niantic's original capacity planning estimates within the first
weeks -- a genuinely enormous, largely unpredictable real spike in
traffic, hitting infrastructure running on Google's cloud platform.
The specific, published account focuses on Google's broader cloud
infrastructure and its own internal orchestration systems (the
direct Borg/Kubernetes lineage from Chapter 53) scaling the backend
services to absorb genuinely unprecedented, unplanned real-world
demand, with Niantic's own engineering team working closely with
Google's infrastructure teams during the event.
WHY THIS BELONGS HERE, regardless of the exact underlying
orchestration technology at the time: it's a vivid, real, public
illustration of EXACTLY the problem this chapter's three-layer model
is built to solve -- automatically maintaining (and rapidly
increasing) a correct number of healthy service instances under
real, unpredictable, extreme demand, without every single scaling
decision requiring a human to manually intervene. This is precisely
the scenario a properly-configured Deployment (Chapter 58's
autoscaling, layered on top) is designed to handle gracefully, and
it's a genuinely useful real story to have in mind for WHY this
chapter's abstractions exist, not just what their YAML syntax looks
like.
Try it yourself
# Deploy something real and watch the three layers
cat > deployment.yaml << 'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
replicas: 3
selector:
matchLabels:
app: web-app
template:
metadata:
labels:
app: web-app
spec:
containers:
- name: web
image: nginx:1.25
ports:
- containerPort: 80
EOF
kubectl apply -f deployment.yaml
kubectl get deployments
kubectl get replicasets
kubectl get pods -l app=web-app
# Kill a pod and watch the ReplicaSet replace it automatically
POD_TO_DELETE=$(kubectl get pods -l app=web-app -o jsonpath='{.items[0].metadata.name}')
test -n "$POD_TO_DELETE" && kubectl delete pod "$POD_TO_DELETE"
sleep 3
kubectl get pods -l app=web-app # still 3 -- a new one appeared
# Update the image and watch a rolling update happen
kubectl set image deployment/web-app web=nginx:1.26
kubectl rollout status deployment/web-app
kubectl get replicasets # TWO ReplicaSets now -- old
# (scaled to 0) and new
kubectl delete -f deployment.yaml
Common mistakes
- Creating bare Pods directly for anything meant to be reliable. No ReplicaSet/Deployment means nothing recreates it if it crashes or its node fails — use a Deployment (or another appropriate controller) for anything beyond a one-off debugging session.
- Being confused by multiple ReplicaSets for one Deployment. This is normal and intentional — old ones (scaled to 0) are kept for fast rollback, up to a configurable history limit.
- Editing a Pod directly to "fix" something. Pods created by a Deployment are managed BY it — a direct edit will likely be overwritten the next time the controller reconciles. Edit the Deployment instead.
Check yourself
- What does a Pod represent, and why is it usually NOT created directly?
- What's the relationship between a Deployment, a ReplicaSet, and a Pod?
- Why does
kubectl get replicasetsoften show more than one entry for a single Deployment?
Further reading
- Docs: Kubernetes' own official "Pods," "ReplicaSet," and "Deployments" documentation pages — the authoritative reference for every field.
- Case study: search "Google Cloud Pokemon Go case study" for the original, published technical account.
- Reference:
kubectl explain deployment.spec— live, built-in documentation for any field, straight from your cluster.