Kubernetes Pods, Deployments, and Services, Explained
Pods, Deployments, and Services are the three Kubernetes objects every beginner must understand. What each one does and how they fit together.
Almost everything you do in Kubernetes comes down to three objects. A Pod runs your containers. A Deployment keeps the right number of Pods running and rolls out new versions safely. A Service gives that ever-changing set of Pods one stable address. Understand these three and the rest of Kubernetes — Ingress, autoscalers, operators — becomes elaboration rather than mystery.
Pods: the smallest deployable unit
Kubernetes never runs a container directly. The smallest thing you can schedule is a Pod: a wrapper around one or more containers that share a network namespace (one IP, one set of ports, localhost between them) and can share storage volumes.
In practice, the overwhelming majority of Pods hold a single container. The multi-container case exists for the sidecar pattern — a helper container riding alongside the main one, handling log shipping, TLS termination, or proxying, and communicating with it over localhost.
The property that shapes everything else: Pods are ephemeral. They are not pets with stable names and addresses. A Pod that crashes isn’t resurrected — a replacement is created, with a new name and a new IP, possibly on a different node. Kubernetes treats Pods as cattle by design, and both of the other two objects exist to make that tolerable.
Why you never create Pods directly
You can write a manifest for a bare Pod and apply it. You almost never should, because a bare Pod has no supervisor: if the node it’s on dies, nothing recreates it.
Instead, you declare how many replicas of a Pod you want, and a controller reconciles reality against that declaration. The controller doing the counting is a ReplicaSet — it watches the cluster and creates or deletes Pods until the actual count matches the desired count. But you don’t usually write ReplicaSets either, because there’s a better abstraction one level up.
Deployments: declarative releases
A Deployment manages ReplicaSets for you and adds the thing production actually needs: safe rollouts. You describe the Pod template and a replica count:
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
replicas: 3
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: my-org/api:v1.4.2
ports:
- containerPort: 8080
When you change the image tag to v1.4.3 and re-apply, the Deployment performs a rolling update: it creates a new ReplicaSet for the new version, brings new Pods up a few at a time, and scales the old set down as the new ones report healthy. Traffic never drops to zero. If the release goes wrong:
kubectl rollout status deployment/api # watch the rollout progress
kubectl rollout undo deployment/api # revert to the previous ReplicaSet
Rollback is cheap because the old ReplicaSet is kept around at zero replicas — undoing a release just scales it back up. This declarative, versioned model is the same configuration-as-data idea that makes YAML the lingua franca of Kubernetes; if you’re curious why the ecosystem settled on it over JSON, see JSON vs YAML.
Services: a stable address for unstable Pods
Now the networking problem. Your three api Pods each have an IP, but those IPs change every time a Pod is replaced. Nothing can hold a reference to a Pod and expect it to keep working.
A Service solves this by providing a single virtual IP and DNS name — api.default.svc.cluster.local — that load-balances across whichever Pods currently match its selector. Callers address the Service; Kubernetes keeps the member list current as Pods come and go. It’s the same stable-front-door idea as a classic load balancer, applied inside the cluster.
apiVersion: v1
kind: Service
metadata:
name: api
spec:
selector:
app: api
ports:
- port: 80
targetPort: 8080
Services come in a few types, each answering “who needs to reach these Pods?”:
| Type | Reachable from | Typical use |
|---|---|---|
| ClusterIP (default) | Inside the cluster only | Service-to-service traffic |
| NodePort | A fixed port on every node | Quick external access, dev clusters |
| LoadBalancer | The internet, via a cloud LB | Production external endpoints |
For HTTP specifically, most clusters put an Ingress (or the newer Gateway API) in front — one entry point that routes by hostname and path to many ClusterIP Services, so you don’t pay for a cloud load balancer per service.
Labels and selectors: the glue
Notice what connects everything: the Deployment finds its Pods with matchLabels: app: api, and the Service finds the same Pods with selector: app: api. Kubernetes objects don’t hold direct references to each other — they select by labels, arbitrary key-value pairs on any object.
This loose coupling is more powerful than it looks. A Service doesn’t know or care that a Deployment manages its Pods; it just matches labels. That’s how canary releases work at the primitive level: run a second Deployment whose Pods carry the same app: api label, and the Service blends traffic across both versions automatically.
Tracing one request
Put it together by following a single request from a user:
- The request hits an external entry point — a LoadBalancer Service or an Ingress.
- The Service consults its current list of healthy, label-matched Pods and forwards the request to one of them.
- The Pod’s container handles the request on its
targetPort. - Meanwhile, the Deployment’s controller is continuously reconciling: if that Pod dies mid-afternoon, a replacement appears, gets the
app: apilabel, passes its health checks, and joins the Service’s pool — with no human involved and no caller aware.
Each object does one job: the Pod runs the code, the Deployment maintains the fleet, the Service makes the fleet addressable.
The takeaway
Pods are the unit of execution — ephemeral by design, never managed by hand. Deployments keep a declared number of Pods running and turn version changes into safe rolling updates with one-command rollback. Services give the whole shifting set a stable name and IP, selected by labels rather than hard references. Nearly every “how do I do X in Kubernetes” answer is a composition of these three objects; learn to read their YAML fluently and the rest of the ecosystem — how Kubernetes relates to Docker, Ingress controllers, autoscaling — slots into place.
Tagged
Keep reading
Chisato · · 4 min read Liveness vs Readiness Probes in Kubernetes, Explained
A liveness probe restarts a stuck container; a readiness probe pulls it from traffic without restarting it. How Kubernetes uses each one.
Chisato · · 5 min read Kubernetes vs Docker: What's the Difference?
Docker builds and runs containers; Kubernetes orchestrates fleets of them. What each tool does, how they work together, and when Compose is enough.
Chisato · · 6 min read What Is Kubernetes? Container Orchestration, Explained
Kubernetes (K8s) is the open-source system for deploying, scaling, and managing containers. A plain-English definition, core concepts, and when to use it.