Kubernetes
Why Docker alone isn't enough once you have more than one container to babysit, and what Kubernetes actually does about it.
The problem Kubernetes solves
Docker packages an app and its dependencies into a container so it runs the same way everywhere. That's the whole job — build an image, run a container from it. Docker doesn't know or care whether that container is one of 3 or one of 300.
In production you're never running one container. You're running many copies of many services, across many machines, and you need something to answer questions Docker was never built to answer:
- Which machine should this container run on right now?
- A container just crashed — who restarts it?
- Traffic doubled — how do I get 5 more copies running, and how do requests find them?
- I'm shipping a new version — how do I roll it out without downtime, and roll back if it's broken?
That coordination layer is container orchestration, and Kubernetes (often shortened to k8s) is the dominant tool for it.
Docker vs Kubernetes — not actually rivals
The "vs" in the title is a bit of a hook — they sit at different layers and normally work together: Docker builds and runs the containers; Kubernetes decides where those containers go, keeps them alive, and scales them.
| Question | Docker | Kubernetes |
|---|---|---|
| Unit of work | A single container | A cluster of containers across many machines |
| Scope | One host | Many hosts, treated as one pool of resources |
| If a container dies | Stays dead unless something restarts it | Detected and automatically restarted |
| Scaling | Manual — run more docker run commands | Declarative — change a number, it makes it true |
| Networking between copies | You wire it up yourself | Built-in service discovery and load balancing |
Core building blocks
A handful of objects account for most of what you'll touch day-to-day:
- Cluster — the whole set of machines Kubernetes manages, split into a control plane (makes decisions) and worker nodes (run the actual workloads).
- Node — one machine (physical or virtual) in the cluster.
- Pod — the smallest deployable unit. Usually one container wrapped with a shared network address and storage; Kubernetes never schedules a bare container, it schedules pods.
- Deployment — a declaration of "I want N copies of this pod running." Kubernetes continuously works to make reality match that declaration — this is what gives you self-healing and easy scaling.
- Service — a stable network address in front of a moving set of pods. Pods get replaced constantly (crashes, rollouts, scaling); the Service is the fixed name/IP everything else talks to.
- Namespace — a way to partition one cluster into logical sub-clusters (e.g.
stagingvsproduction).
The core loop: declarative, not step-by-step
You don't tell Kubernetes how to do something — you describe the end state you want (usually in a YAML file) and Kubernetes' control plane continuously reconciles reality toward it.
# deployment.yaml (trimmed)
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 3
template:
spec:
containers:
- name: web
image: my-registry/web:1.4.0
Applying that file is a promise, not a one-time action:
kubectl apply -f deployment.yaml
From then on, if a pod crashes, a node dies, or someone deletes a pod by hand, the control plane notices replicas: 3 is no longer true and starts a new pod to fix it — with no human in the loop. That reconciliation loop is the core idea underneath everything Kubernetes does.
Key takeaways
- Docker answers "how do I package and run this one thing." Kubernetes answers "how do I run many of these things, reliably, across many machines."
- You describe desired state; Kubernetes' job is to keep making that state true.
- Pods are ephemeral and expected to die — Deployments keep the count right, Services give the world a stable address to reach them at.
- You reach for Kubernetes once "restart it by hand" and "just SSH in and run another container" stop scaling — not for a single side project on a single box.