Pods & Workloads
You’d expect Kubernetes’ smallest unit to be the container. It isn’t — it’s the Pod. Getting this right is the foundation for everything above it, so we start there, then climb the ladder of workload types that wrap Pods to give you the behaviors from the why-orchestration page: healing, scaling, safe rollouts.
The thread for this page: what manual, error-prone step does each workload type remove — and how does it make production safer?
Why a Pod, not a container?
Section titled “Why a Pod, not a container?”A Pod is one or more containers that are always scheduled together, on the same node, sharing a
network namespace (the same IP and port space) and able to share storage volumes. To the containers
inside a Pod, each other’s processes are reachable on localhost.
Why introduce this wrapper at all? Because sometimes a “thing you run” is genuinely a tiny team of processes that must live and die together — a main app plus a sidecar that ships its logs, or a proxy that handles its TLS. Those helpers need to be co-located, share the network, and be scheduled as a unit. The Pod is that unit. The common case is still one container per Pod; the Pod is just the box Kubernetes actually places, replaces, and counts.
┌──────────────── Pod (one IP, shared by all containers) ───────────────┐ │ │ │ ┌──────────────┐ ┌──────────────────┐ │ │ │ app container │◄──────►│ sidecar (e.g. log │ both reach each │ │ │ :8080 │ localhost│ shipper / proxy) │ other on localhost │ │ └──────────────┘ └──────────────────┘ │ │ shared network namespace + optional shared volumes │ └────────────────────────────────────────────────────────────────────────┘The ladder of workload types
Section titled “The ladder of workload types”Each workload type is a controller (recall the architecture) that manages Pods to achieve a particular goal.
ReplicaSet — keep N copies running
Section titled “ReplicaSet — keep N copies running”A ReplicaSet has one job: ensure exactly N matching Pods exist at all times. Kill one and it makes another. This is the healing-and-scaling primitive. You rarely create one directly, though, because it can’t do rollouts — for that you use a Deployment, which manages ReplicaSets for you.
Deployment — safe rollouts and one-command rollback
Section titled “Deployment — safe rollouts and one-command rollback”A Deployment is the workhorse for stateless apps. It owns a ReplicaSet, and when you change the image, it performs a controlled rolling update: it creates a new ReplicaSet, brings up new Pods a few at a time, waits for them to pass health checks, and scales the old ReplicaSet down — never dropping below your availability floor. If the new version is broken, one command rolls it back.
apiVersion: apps/v1kind: Deploymentmetadata: name: webspec: replicas: 4 selector: matchLabels: { app: web } strategy: type: RollingUpdate rollingUpdate: maxUnavailable: 1 # never drop more than 1 below desired during a rollout maxSurge: 1 # may run 1 extra during a rollout template: metadata: labels: { app: web } spec: containers: - name: web image: myapp:1.4.0 ports: - containerPort: 8080 readinessProbe: # don't send traffic until this passes httpGet: { path: /healthz, port: 8080 } initialDelaySeconds: 3 periodSeconds: 5kubectl apply -f web.yamlkubectl set image deployment/web web=myapp:1.5.0 # trigger a rolling updatekubectl rollout status deployment/web # watch it progresskubectl rollout undo deployment/web # roll back to the previous versionkubectl rollout history deployment/web # see past revisionsThis is the rollout dance from the why-orchestration page — the careful, stateful sequence a human
does inconsistently under pressure — reduced to a declared strategy plus a readinessProbe. The probe
is what makes it safe: a new Pod gets traffic only once it says it’s ready, and a rollout stalls
rather than marching forward into an outage.
DaemonSet — one Pod per node
Section titled “DaemonSet — one Pod per node”A DaemonSet runs exactly one copy of a Pod on every node (or every node matching a selector), and automatically adds a copy when a new node joins. This is how you run per-node infrastructure — a log collector, a metrics agent, a CNI plugin. The manual step it removes: remembering to install the agent on every box, forever, including boxes that don’t exist yet.
Job and CronJob — run to completion
Section titled “Job and CronJob — run to completion”Deployments assume a process that stays up. A Job is for work that finishes: a batch import, a migration, a report. The Job runs Pods until a set number complete successfully, retrying failures. A CronJob creates Jobs on a schedule — the Kubernetes-native replacement for a crontab scattered across machines.
apiVersion: batch/v1kind: CronJobmetadata: name: nightly-reportspec: schedule: "0 2 * * *" # 02:00 every day jobTemplate: spec: template: spec: restartPolicy: OnFailure containers: - name: report image: myapp:1.5.0 command: ["python", "generate_report.py"]Choosing the right one
Section titled “Choosing the right one”| You want to… | Use |
|---|---|
| Run a stateless service, with rollouts | Deployment |
| Just keep N identical Pods alive (rarely direct) | ReplicaSet |
| Run one agent on every node | DaemonSet |
| Run a task that finishes once | Job |
| Run a task on a schedule | CronJob |
| Run stateful Pods with stable identity/storage | StatefulSet — see Storage & Stateful |
Every one of these is a controller wrapping Pods, and every one works the same way underneath: declared desired state, a loop driving actual toward it. That loop is the next page, and it is the idea that ties this whole Part together.
The architect’s lens
Section titled “The architect’s lens”Step back from the ladder of workload types and ask why the Pod — and the controllers above it — exist:
- Why does it exist? Because the unit you actually run is sometimes a tiny team of processes that must live and die together — an app plus a sidecar log shipper or TLS proxy. The Pod is that co-scheduled unit, sharing one IP and namespace; the workload controllers above it (ReplicaSet, Deployment, DaemonSet, Job) give you healing, scaling, and safe rollouts.
- What problem does it solve? It makes self-healing and safe deploys declarative: a Deployment’s
readinessProbeplus a rolling-update strategy (maxUnavailable: 1,maxSurge: 1) turns the error-prone human rollout dance into a stalled-on-failure, never-below-the-floor sequence. - What are the trade-offs? Pods are cattle, not pets — never repaired, always replaced with a new IP — so you gain replaceability but must design every workload to tolerate sudden death and address things by Service, not Pod IP.
- When should I avoid it? Pick the wrong wrapper and it bites: a Deployment for work that should finish (use a Job/CronJob), or a bare Pod with no controller — which won’t be recreated when it dies, throwing away the self-healing the whole model is built on.
- What breaks if I remove it? Without the controllers, a crash is permanent (no replacement), a
per-node agent must be installed on every box by hand instead of a DaemonSet, scheduled work scatters
back into crontabs across machines, and a
CrashLoopBackOff— the back-off healing loop working as designed — is something you’d have to reimplement.
Check your understanding
Section titled “Check your understanding”- Kubernetes runs Pods, not containers. What does a Pod give its containers that separate containers wouldn’t share, and when do you actually want more than one container in a Pod?
- Why are Pods described as “cattle, not pets,” and how does that property enable self-healing?
- A Deployment manages a ReplicaSet rather than Pods directly. What does that extra layer buy you?
- What does a
readinessProbedo during a rolling update, and why is it the thing that makes the rollout safe rather than just automated? - Match the workload type to the need: a nightly database backup; a per-node metrics agent; a stateless API that needs zero-downtime deploys.
Show answers
- A Pod gives its containers a shared network namespace (the same IP and port space, so they reach each other on
localhost) and optional shared storage volumes, and schedules them together on one node. You want more than one container when helpers must be co-located with the app — a sidecar shipping logs, or a proxy terminating TLS — but the common case is still one container per Pod. - Because a Pod is disposable and never repaired — if it dies it’s replaced by a brand-new Pod with a new IP, not fixed in place. That replaceability is exactly what makes self-healing possible: a controller can freely delete and recreate Pods to drive actual state back to desired.
- Rollouts and rollback. A ReplicaSet only keeps N Pods alive; a Deployment owns ReplicaSets and orchestrates a controlled rolling update (new ReplicaSet up a few Pods at a time, old one down) plus a one-command
rollout undo. - A
readinessProbedecides when a new Pod is ready to receive traffic — a Pod gets no traffic until the probe passes. That makes the rollout safe rather than merely automated: a broken new version never receives users, and the rollout stalls instead of marching forward into an outage. - Nightly backup → CronJob (runs a Job on a schedule, to completion); per-node metrics agent → DaemonSet (one Pod per node, auto-added to new nodes); zero-downtime stateless API → Deployment (rolling updates with readiness probes).