Part 3 · Containers
There is a sentence that has wasted more engineering hours than almost any other: “works on my machine.” A developer runs the app on their laptop, it passes every test, they hand it off — and it falls over in staging. Or in production. Or only on the one server that happens to have a slightly older library. The code didn’t change between the laptop and the server. The environment did.
That gap — between the environment where software is built and the environment where it runs — is the problem Part 3 is about. Containers are the industry’s answer to it.
What “works on my machine” actually means
Section titled “What “works on my machine” actually means”Your laptop is not just your code. It is your code plus a specific Python version, a specific glibc, a dozen system libraries installed over two years, an environment variable you set once and forgot, and a config file in your home directory. The app depends on all of it. When you ship “the app,” you ship only the code — and you assume the destination has the rest. That assumption is the bug.
YOUR LAPTOP THE SERVER ┌─────────────────────┐ ┌─────────────────────┐ │ your code │ ── ship ─► │ your code │ ✓ │ python 3.11 │ │ python 3.9 │ ✗ subtly different │ libssl 3.0 │ │ libssl 1.1 │ ✗ wrong version │ TZ=America/Toronto │ │ TZ=UTC │ ✗ unset │ /etc/app.conf │ │ (missing) │ ✗ never copied └─────────────────────┘ └─────────────────────┘ "works" "broken"The old fixes were all manual and all fragile: a wiki page of setup steps that drifts out of date, a hand-maintained provisioning script, an ops engineer who “just knows” what the box needs. Every one of those is a manual, error-prone step performed by a human under deadline pressure. This is the recurring thread of the whole book — and containers attack it head-on. A container is the entire environment, packaged as one artifact, so the thing you tested is byte-for-byte the thing that runs. That is how containers make production safer: they delete the gap where “it changed in transit” bugs live.
The roadmap for Part 3
Section titled “The roadmap for Part 3”We build in dependency order. Each page only uses ideas the previous ones established.
| Page | The question it answers |
|---|---|
| Why Containers | What problem do they solve that VMs don’t, and what is “the artifact that runs identically everywhere”? |
| Namespaces & cgroups | What is a container, mechanically? (Spoiler: there’s no “container” object in the kernel.) |
| Images & Layers | How is an environment packaged so it’s reproducible and cheap to ship? |
| Dockerfiles | How do you describe, in version-controlled code, exactly how to build that environment? |
| Registries | Where do images live, how are they shared, and why is latest a trap? |
| Container Networking & Volumes | How do containers talk to the world and where does data that must survive a restart go? |
By the end you’ll be able to take an app, write a Dockerfile, build a small reproducible image, push
it to a registry, and run it with a network and persistent storage — and explain why each step
removes a manual failure point.
Where this leads
Section titled “Where this leads”Containers solve “one box, one app, runs anywhere.” But production runs many containers across many machines, and they crash, scale, and move. Making a fleet of containers behave is a different problem — that’s Part 4 · Orchestration with Kubernetes. And the act of automatically building and shipping these images on every commit is Part 5 · CI/CD. Containers are the unit everything later is built from. Start here.
Check your understanding
Section titled “Check your understanding”- In your own words, what does “works on my machine” actually mean — what is the developer implicitly shipping versus explicitly shipping?
- Name two old, manual fixes for environment drift and explain why each is error-prone.
- What is the one-sentence claim about what a container really is that the rest of Part 3 builds on?
- How does packaging the whole environment as one artifact make production safer, not just more convenient?
- Containers solve “runs anywhere” for one app on one box. Name the two later problems (and their Parts) that containers alone do not solve.
Show answers
- The developer explicitly ships only the code, but implicitly depends on a whole environment — a specific language/runtime version, system libraries like glibc, environment variables, and config files in their home directory. “Works on my machine” means the code plus all that unshipped context.
- Examples: a wiki page of setup steps (drifts out of date the moment anything changes) and a hand-maintained provisioning script or an ops engineer who “just knows” the box (relies on human memory under deadline pressure). Each is a manual step a human can get subtly wrong.
- A container is not a tiny virtual machine — it is a normal Linux process wearing a costume. Everything in Part 3 follows from that one claim.
- You run the exact bytes you tested in production rather than rebuilding the environment there, so there’s no gap in transit where staging and production silently diverge. It’s not just convenience — it deletes the place “it changed on the way” bugs live, which is a safety property.
- Running a fleet of containers across many machines that crash, scale, and move — Part 4 · Orchestration — and automatically building and shipping the images on every commit — Part 5 · CI/CD.