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 owns ReplicaSets so you can roll out a new image and roll back.

A Deployment is what you use to run almost everything on Kubernetes. You tell it what should be running and how many copies, and it keeps reality matching that. If a copy crashes at 3 a.m., you do not get paged; it brings up a new one.

A few words you will see everywhere. A container is your app plus what it needs to run, so it behaves the same on a laptop or a server. An image is the read-only template a container is built from; nginx:1.25 is the name and version. A Pod is the smallest thing Kubernetes runs; for now, a thin wrapper around one container. A cluster is the machines Kubernetes manages. A node is one of those machines, where pods run.

One file, and it manages the rest

Underneath, a Deployment creates a ReplicaSet. You tell the ReplicaSet to keep three copies alive; it replaces any copy that dies so the count does not drift. You almost never build a ReplicaSet by hand. The Deployment adds what a bare ReplicaSet cannot: a rollout of a new version without taking the whole app offline, and a rollback in seconds if the new one misbehaves. You write this in YAML (YAML Ain't Markup Language): indented plain text. Keep the file in version control (Git records every change), review it, and you can stand the same app 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. Deleting everything would take the app dark while new copies boot. A Deployment swaps pods a few at a time, waiting for each new one to report healthy before retiring an old one. Watch it 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. It scales the new ReplicaSet up and the old one down.

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