Part 16 — Kubernetes fundamentals
Docker (Part 15) runs one container well, on one machine. This final part is the problem that remains once you have hundreds of containers spread across many machines — and why Kubernetes, rather than a bigger shell script built on Part 12's material, is what actually fills that gap.
Chapter 53 — Why Kubernetes exists (the problem Docker alone doesn't solve)
In one sentence
Docker runs ONE container on ONE machine well; Kubernetes exists to answer
the much harder question — across a FLEET of machines, which containers run
where, what happens when a machine dies, how do they find each other, and
how does the whole thing scale — automatically, continuously, without a
human manually running docker run on the right server every time.
Why this matters
Understanding WHY Kubernetes exists, not just its commands, is what lets you reason about whether you actually need it, and what problem each of its pieces (Parts 55-58) is specifically solving.
How it actually works
RUNNING ONE CONTAINER, on ONE machine, with `docker run`, you already
fully understand (Part 15). Real production systems need FAR more:
- MANY containers, across MANY machines (a fleet), because one
machine's capacity isn't enough, and because a single machine is
a single point of failure.
- if a MACHINE DIES, the containers that were running on it need to
be RESTARTED somewhere else, AUTOMATICALLY -- nobody wants a
human paged at 3am to manually run `docker run` on a replacement
server.
- containers need to FIND EACH OTHER reliably, even as individual
instances come and go, are rescheduled, or scale up and down
(Chapter 56).
- the whole fleet needs to SCALE -- more instances of a busy
service during high traffic, fewer during quiet periods
(Chapter 58) -- again, ideally without a human manually
intervening every time.
- deploying a NEW VERSION of an application across many running
instances needs to happen WITHOUT DOWNTIME, and be safely
REVERSIBLE if something's wrong (Chapter 60).
KUBERNETES is, fundamentally, a system that takes a DECLARATIVE
DESCRIPTION of what you want ("I want 5 copies of this container
running, with these resource limits, exposed on this port") and
CONTINUOUSLY, AUTOMATICALLY works to make reality match that
description -- restarting failed instances, rescheduling them onto
healthy machines, routing traffic to whichever instances are
currently healthy -- all without a human re-issuing the request
every time something changes. This "reconcile actual state toward
desired state, continuously, forever" idea is the single most
important concept to carry into every chapter that follows.
Real-world example
Kubernetes is not a from-scratch invention -- its own creators have
been explicit, in a well-documented, published 2016 paper ("Borg,
Omega, and Kubernetes: Lessons Learned from Three Container-
Management Systems over a Decade," written by Google engineers and
published through the ACM) about its direct lineage: Kubernetes was
built by engineers who had spent YEARS operating Google's INTERNAL
cluster-management systems -- Borg (which has run essentially all of
Google's own production workloads, including Search and Gmail, since
the mid-2000s) and its successor Omega -- and Kubernetes was
deliberately designed to bring the SAME hard-won lessons from running
containers at that massive, real, internal scale to the wider
public, as an open-source project (Kubernetes was announced by
Google in 2014).
The paper itself is genuinely worth reading: it candidly describes
both what worked and what Google's own engineers considered MISTAKES
in Borg's original design, and how Kubernetes deliberately corrected
for them (the shift toward Kubernetes' now-familiar declarative, API-
driven model was, per the paper, a direct response to specific,
real, operational pain points Google had experienced running Borg at
scale for over a decade). This lineage is precisely why Kubernetes'
design feels the way it does throughout Parts 16-17: it's the
distilled, public version of one of the largest, longest-running
real-world experiments in "how do you actually run containers
reliably at scale" in the industry's history.
Try it yourself
# You'll need a local cluster for the rest of this Part -- set one up
# now (kind = "Kubernetes IN Docker," runs a real cluster using
# containers as the "nodes," genuinely excellent for learning)
# Install kind: https://kind.sigs.k8s.io/docs/user/quick-start/
# Install kubectl: https://kubernetes.io/docs/tasks/tools/
kind create cluster --name learning
kubectl cluster-info
kubectl get nodes # your single-node "cluster" -- but
# a REAL Kubernetes API server,
# scheduler, and kubelet are all
# genuinely running
kubectl get namespaces
Common mistakes
- Reaching for Kubernetes for a single-server hobby project. It solves
fleet-scale problems — genuinely excellent tooling, genuinely unnecessary
complexity for something
docker compose(Chapter 51) already handles well. - Thinking Kubernetes replaces Docker. Kubernetes ORCHESTRATES
containers across many machines; something still has to actually RUN
them on each machine (a container runtime — historically often Docker's
own runtime, now commonly
containerddirectly). - Assuming "declarative" means "instant." Reconciliation toward desired state happens continuously, but it's not instantaneous — there's real, observable time between "I declared 5 replicas" and "5 replicas are actually running and healthy" (Chapter 59 covers watching this happen).
Check yourself
- What specific problems does Kubernetes solve that plain Docker, running on one machine, does not?
- What is the "reconcile actual state toward desired state" idea, and why is it central to everything Kubernetes does?
- What real, internal Google system directly inspired Kubernetes' design?
(Answers: Appendix E.)
Further reading
- Paper: "Borg, Omega, and Kubernetes" (Google, 2016, published via ACM Queue) — genuinely readable, genuinely worth reading in full.
- Docs: Kubernetes' own official documentation, "Kubernetes Components" overview page — the authoritative starting point.
- Tool:
kind(kind.sigs.k8s.io) — the local-cluster tool used throughout the rest of this Part.