CoursesKubernetes fundamentalsDeployments: the one you will use

Deployments: the one you will use

Managing pods the normal way.

Beginner10 min · lesson 8 of 24
In plain terms
A Deployment is the store manager above that shift manager — it also swaps everyone into new uniforms smoothly, and puts them back in the old ones if the new batch is bad.

You set a thermostat once and then mostly forget about it. You pick the temperature you want, and it keeps the room there, clicking the heater on and off by itself. A Deployment does that same job for your app: you tell Kubernetes what should be running and how many copies you want, and it keeps reality matching that request. If a copy crashes at 3 a.m., you don't get paged; the Deployment just brings up a new one. This is the object you'll reach for to run almost everything on Kubernetes.

A few words first, because you'll see them everywhere. A container is a sealed-up copy of your app with everything it needs to run tucked inside, so it behaves the same on your laptop as it does on a server. An image is the read-only recipe a container is built from; nginx:1.25 is an image name followed by its version number. A Pod is the smallest thing Kubernetes runs, and for now you can treat it as a thin wrapper around a single container. A cluster is the whole group of machines Kubernetes manages for you. A node is one of those machines, the place where your pods actually run. Learn those few words and the rest clicks into place.

One file, and it manages the rest

Underneath, a Deployment creates something called a ReplicaSet. Think of a ReplicaSet as a head-counter. You tell it to keep three copies alive, and it does exactly that, replacing any copy that dies so the number never drifts. You almost never build one by hand. The Deployment makes it for you and adds two tricks a bare ReplicaSet can't do on its own: it can roll out a new version without taking the whole thing offline, and it can put the old version back in seconds if the new one misbehaves. You write all of this down in a YAML file. YAML (it stands for "YAML Ain't Markup Language") is just plain text that uses indentation to spell out settings. That file becomes your source of truth: keep it in version control (a tool like Git that records every change), review it like code, and stand the same app back up on any cluster.

hello.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello
spec:
replicas: 3
selector:
matchLabels:
app: hello
template:
metadata:
labels:
app: hello
spec:
containers:
- name: web
image: nginx:1.25
ports:
- containerPort: 80

Hand the file to the cluster with kubectl apply. kubectl is the command-line tool you use to talk to a Kubernetes cluster; you'll type it a hundred times a day. The apply part means 'make the cluster match this file.' Then ask what you got.

terminal
$ kubectl apply -f hello.yaml
deployment.apps/hello created
$ kubectl get deployment hello
NAME READY UP-TO-DATE AVAILABLE AGE
hello 3/3 3 3 18s
$ kubectl get pods -l app=hello
NAME READY STATUS RESTARTS AGE
hello-6d8f4c9b7d-2mkzq 1/1 Running 0 18s
hello-6d8f4c9b7d-9wp4t 1/1 Running 0 18s
hello-6d8f4c9b7d-lr7xn 1/1 Running 0 18s

That READY column showing 3/3 means all three copies are up and serving requests. UP-TO-DATE tells you how many pods are running the version you last asked for, and AVAILABLE is how many have stayed healthy long enough to take real users. The odd-looking tails on the pod names, like 6d8f4c9b7d-2mkzq, are normal: Kubernetes gives every pod a unique name so it can tell them apart, and you don't pick them or need to memorize them. That number you set, replicas: 3, is also your dial for scaling. Bump it to 5, apply again, and two more pods show up; drop it back and the extras go away. That's all scaling means at this level.

Changing it without downtime

Say a newer version is ready to ship. You could delete everything and start over, but users would watch the app go dark while the new copies boot. A Deployment does it the calm way. Think of repainting a long fence one plank at a time while people keep leaning on it, so there's never an open gap for anyone to fall through. You change the image, and the Deployment swaps pods a few at a time, waiting for each new one to report healthy before retiring an old one. Watch it happen with rollout status.

terminal
$ kubectl set image deployment/hello web=nginx:1.26
deployment.apps/hello image updated
$ kubectl rollout status deployment/hello
Waiting for deployment "hello" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "hello" rollout to finish: 2 out of 3 new replicas have been updated...
deployment "hello" successfully rolled out

When a rollout goes wrong

Not every new version is a good one. Maybe you fat-finger the image tag, or the build you pushed is broken. This is the moment beginners dread, so let's cause it on purpose. Here we point the Deployment at nginx:1.99, a tag that was never published, then ask for the rollout status.

terminal
$ kubectl set image deployment/hello web=nginx:1.99
deployment.apps/hello image updated
$ kubectl rollout status deployment/hello
Waiting for deployment "hello" rollout to finish: 1 out of 3 new replicas have been updated...
^C

It just sits there, and that stall is the Deployment protecting you. It started one new pod, never saw it turn healthy, and so refused to touch the three old ones. Your app keeps serving throughout. Press Ctrl+C and look at the pods to see the split.

terminal
$ kubectl get pods -l app=hello
NAME READY STATUS RESTARTS AGE
hello-6d8f4c9b7d-2mkzq 1/1 Running 0 6m
hello-6d8f4c9b7d-9wp4t 1/1 Running 0 6m
hello-6d8f4c9b7d-lr7xn 1/1 Running 0 6m
hello-7c4d9f8b5c-x2p9q 0/1 ImagePullBackOff 0 40s

Three old pods still Running, one new pod stuck. ImagePullBackOff means the node tried to download the image, failed, and now waits a little longer between each retry. To find out why, describe the broken pod and read the Events list at the bottom, where Kubernetes narrates, line by line, what it tried to do with this pod.

terminal
$ kubectl describe pod hello-7c4d9f8b5c-x2p9q
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 50s default-scheduler Successfully assigned default/hello-7c4d9f8b5c-x2p9q to node-1
Normal Pulling 35s (x2 over 49s) kubelet Pulling image "nginx:1.99"
Warning Failed 33s (x2 over 47s) kubelet Failed to pull image "nginx:1.99": manifest for nginx:1.99 not found
Warning Failed 33s (x2 over 47s) kubelet Error: ErrImagePull
Normal BackOff 19s (x3 over 46s) kubelet Back-off pulling image "nginx:1.99"
Warning Failed 19s (x3 over 46s) kubelet Error: ImagePullBackOff

There it is, on the Failed line: manifest for nginx:1.99 not found. The tag doesn't exist, so the node has nothing to run. Those events also name the two parts that touched the pod: the scheduler picked a node for it, and the kubelet (the agent on that node) tried and failed to pull the image. A misspelled private image or a missing pull secret looks the same. You don't repair this pod; you put the last known-good version back.

terminal
$ kubectl rollout undo deployment/hello
deployment.apps/hello rolled back
$ kubectl rollout status deployment/hello
deployment "hello" successfully rolled out
$ kubectl get pods -l app=hello
NAME READY STATUS RESTARTS AGE
hello-6d8f4c9b7d-2mkzq 1/1 Running 0 8m
hello-6d8f4c9b7d-9wp4t 1/1 Running 0 8m
hello-6d8f4c9b7d-lr7xn 1/1 Running 0 8m

The broken pod is gone and the three good ones are untouched. Because the old ReplicaSet was still sitting there, the rollback points traffic back at pods that were already built, so it lands in seconds. The safety net worth memorizing: a bad image stalls a rollout, it doesn't take your running app down with it. kubectl rollout status catches the stall; kubectl rollout undo gets you out of it.

How a change flows down
1You edit theDeploymentchange the image or the…2It updates theReplicaSetthe head-counter for your pods3The ReplicaSetadjusts the Podsadds, removes, or replaces…4Pods run on nodesyour app is live and serving…
You only ever touch the top box. Every change flows down the chain on its own.

A Deployment is the object you will use day to day. It owns ReplicaSets, rolls out new pod templates, and keeps revision history so you can undo. Think of it as the product manager for your pods: it decides which ReplicaSet should be big and which should shrink.

Rolling updates trade speed for safety. maxUnavailable and maxSurge decide how many pods can be down or extra during a change. Prefer a slower rollout with readiness probes over a blast that takes the Service to zero endpoints.

In production, record the image (digest) you rolled and who approved it. kubectl rollout history is your friend after an incident when people argue about what changed.

Try this

Apply a Deployment, watch Ready replicas, then change the image and observe the rollout status.

terminal
$ kubectl create deployment hello --image=nginx:1.26 --replicas=3
deployment.apps/hello created
$ kubectl get deploy hello
NAME READY UP-TO-DATE AVAILABLE AGE
hello 3/3 3 3 9s
$ kubectl set image deployment/hello nginx=nginx:1.27
deployment.apps/hello image updated
$ kubectl rollout status deployment/hello
Waiting for deployment "hello" rollout to finish: 1 out of 3 new replicas have been updated...
deployment "hello" successfully rolled out
$ kubectl rollout history deployment/hello
deployment.apps/hello
REVISION CHANGE-CAUSE
1 <none>
2 <none>
$ kubectl delete deployment hello
deployment.apps "hello" deleted

Takeaway

Deployments manage ReplicaSets and rollouts. Ship with readiness-aware rolling updates, keep history, and verify with rollout status instead of hoping the Service stayed healthy.

Match the labels
In the file, the selector (app: hello) and the labels on the pod template (app: hello) have to be the exact same text. That match is how the Deployment knows which pods count as its own, the way a coat-check tag has to match the ticket in your pocket. If the two disagree, the cluster either rejects the file outright or the Deployment ends up managing no pods at all. It's one of the most common first-day mistakes, and an easy one to spot once you know to check for it.
Quick check
01You update a Deployment to an image tag that doesn't exist. What happens to the app your users are hitting?
Correct — The Deployment won't retire a healthy old pod until a new one reports ready, so a bad image just stalls the rollout; your app stays up.
Incorrect — No. The Deployment keeps the old, healthy pods running and only stalls. Refusing to kill good pods before new ones are ready is the safety net.
Incorrect — No. Kubernetes runs exactly the tag you asked for; it won't guess a different one. You recover it with kubectl rollout undo.
Incorrect — No. The Deployment stays put; only the one new pod fails to start. Your old pods are untouched.
02In the output of kubectl get deployment, what does the UP-TO-DATE column tell you?
Incorrect — That describes AVAILABLE, a different column — Pods that have been healthy long enough to serve.
Incorrect — Update history isn't shown here; kubectl rollout history is what lists past revisions.
Correct — UP-TO-DATE is the count of Pods already updated to the latest version you requested.
Incorrect — There's no maximum column; replicas sets the target and READY shows how many are up.
03A rollout to a bad tag has stalled with your three original Pods still Running. You run kubectl rollout undo and it completes in seconds. Why so fast?
Incorrect — A cached image would still need Pods started and readied, so that isn't what makes undo instant.
Correct — the previous ReplicaSet's Pods were never deleted, so the rollback lands immediately.
Incorrect — undo doesn't skip readiness; the old Pods were already ready and running the entire time.
Incorrect — No rebuild happens — the lesson stresses the previous revision is kept ready to go.

Related