Deployments: the one you will use
Managing pods the normal way.
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.
apiVersion: apps/v1kind: Deploymentmetadata:name: hellospec:replicas: 3selector:matchLabels:app: hellotemplate:metadata:labels:app: hellospec:containers:- name: webimage: nginx:1.25ports:- 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.
$ kubectl apply -f hello.yamldeployment.apps/hello created$ kubectl get deployment helloNAME READY UP-TO-DATE AVAILABLE AGEhello 3/3 3 3 18s$ kubectl get pods -l app=helloNAME READY STATUS RESTARTS AGEhello-6d8f4c9b7d-2mkzq 1/1 Running 0 18shello-6d8f4c9b7d-9wp4t 1/1 Running 0 18shello-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.
$ kubectl set image deployment/hello web=nginx:1.26deployment.apps/hello image updated$ kubectl rollout status deployment/helloWaiting 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.
$ kubectl set image deployment/hello web=nginx:1.99deployment.apps/hello image updated$ kubectl rollout status deployment/helloWaiting 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.
$ kubectl get pods -l app=helloNAME READY STATUS RESTARTS AGEhello-6d8f4c9b7d-2mkzq 1/1 Running 0 6mhello-6d8f4c9b7d-9wp4t 1/1 Running 0 6mhello-6d8f4c9b7d-lr7xn 1/1 Running 0 6mhello-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.
$ 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-1Normal 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 foundWarning Failed 33s (x2 over 47s) kubelet Error: ErrImagePullNormal 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.
$ kubectl rollout undo deployment/hellodeployment.apps/hello rolled back$ kubectl rollout status deployment/hellodeployment "hello" successfully rolled out$ kubectl get pods -l app=helloNAME READY STATUS RESTARTS AGEhello-6d8f4c9b7d-2mkzq 1/1 Running 0 8mhello-6d8f4c9b7d-9wp4t 1/1 Running 0 8mhello-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.
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.
$ kubectl create deployment hello --image=nginx:1.26 --replicas=3deployment.apps/hello created$ kubectl get deploy helloNAME READY UP-TO-DATE AVAILABLE AGEhello 3/3 3 3 9s$ kubectl set image deployment/hello nginx=nginx:1.27deployment.apps/hello image updated$ kubectl rollout status deployment/helloWaiting for deployment "hello" rollout to finish: 1 out of 3 new replicas have been updated...deployment "hello" successfully rolled out$ kubectl rollout history deployment/hellodeployment.apps/helloREVISION CHANGE-CAUSE1 <none>2 <none>$ kubectl delete deployment hellodeployment.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.