Articles

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.

Chisato Chisato · · 5 min read
A CI/CD pipeline of connected stages

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?”:

TypeReachable fromTypical use
ClusterIP (default)Inside the cluster onlyService-to-service traffic
NodePortA fixed port on every nodeQuick external access, dev clusters
LoadBalancerThe internet, via a cloud LBProduction 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:

  1. The request hits an external entry point — a LoadBalancer Service or an Ingress.
  2. The Service consults its current list of healthy, label-matched Pods and forwards the request to one of them.
  3. The Pod’s container handles the request on its targetPort.
  4. Meanwhile, the Deployment’s controller is continuously reconciling: if that Pod dies mid-afternoon, a replacement appears, gets the app: api label, 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.

Chisato 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.

#Kubernetes #Docker #DevOps