Kubernetes for People Who Ship Services
Kubernetes has a reputation for complexity, most of which you can ignore at first. Here's the minimum mental model — pods, deployments, services — that lets you actually run a containerized backend and understand what's happening.
Kubernetes is intimidating because people learn it as a giant pile of YAML and acronyms. But underneath, it's answering one question: how do you keep a set of containers running, reachable, and healthy across a fleet of machines, without babysitting them? If you frame it that way, three concepts get you most of the way. This is the mental model I wish I'd started with.
The core idea: declare, don't command
The mindset shift that makes Kubernetes click: you don't tell it what to do, you tell it what you want to be true. "I want three copies of this container running." Kubernetes then works continuously to make reality match that declaration — if a container crashes, it starts a new one; if a machine dies, it reschedules the work elsewhere.
This is declarative and self-healing. You describe the desired state; the control loop keeps closing the gap. Almost everything else is a variation on that theme.
Pod: the smallest unit
A pod wraps one container (usually) plus its runtime context. It's the thing Kubernetes actually schedules onto a machine. You rarely create pods directly, because a bare pod is mortal — if it dies, it's just gone. You want something watching over it. That's the next layer.
Deployment: keep N copies running
A Deployment is what you actually write. It says "keep 3 replicas of this pod running," and it means it — kill a pod and the Deployment immediately replaces it to restore the count.
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
replicas: 3 # desired: always 3 running
selector:
matchLabels: { app: api }
template:
metadata:
labels: { app: api }
spec:
containers:
- name: api
image: myregistry/api:1.4.0
ports:
- containerPort: 8080The Deployment also gives you rolling updates: change the image tag and it replaces pods gradually — a few at a time — so there's no downtime, and it can roll back if the new version fails its health checks.
Service: a stable address for moving pods
Pods are ephemeral — they come and go, and each gets a new IP. So how does anything reliably reach them? A Service is a stable name and address that load-balances across whatever pods currently match its label selector.
apiVersion: v1
kind: Service
metadata:
name: api
spec:
selector:
app: api # routes to every pod labeled app=api
ports:
- port: 80
targetPort: 8080Now other services call api and Kubernetes routes to a healthy pod, no matter how many there are or how often they're replaced. The Service is the stable front door; the pods behind it churn freely.
Health checks are how self-healing works
Kubernetes can only heal what it can observe, so it relies on two probes you define:
- Liveness probe — "is this pod alive?" If it fails, Kubernetes restarts the pod. Catches deadlocks and hangs.
- Readiness probe — "is this pod ready for traffic?" If it fails, Kubernetes stops routing to it (but doesn't kill it). Catches "started but still warming up."
livenessProbe:
httpGet: { path: /health, port: 8080 }
readinessProbe:
httpGet: { path: /ready, port: 8080 }Skip these and you lose the whole point — Kubernetes will happily route traffic to a pod that's booting or wedged, because you never told it how to tell the difference.
Do you even need it?
Honest answer: often not yet. Kubernetes earns its complexity when you're running many services, need zero-downtime deploys at scale, and have the traffic to justify autoscaling across a fleet. For a single service with modest traffic, a managed platform (a PaaS, or serverless) gives you most of the benefits — self-healing, rolling deploys, scaling — with a fraction of the operational surface.
But when you do need to orchestrate containers across machines, this model — declare the desired state, let Deployments keep pods alive, let Services give them a stable address, let probes drive self-healing — is the foundation everything else in Kubernetes stands on.