Chapter 119·Beginner·8 min read
Why Containers Exist (and Kill 'Works on My Machine')
A plain-English introduction to containers — the 'works on my machine' problem they solve, what a container actually is, how they differ from virtual machines, why they start in milliseconds, and why Docker made them universal. The foundation before you run a single container.
July 18, 2026
You wrote code. It runs perfectly on your laptop. You send it to a teammate, or push it to a server, and it breaks — a missing library, a different version of the language, a setting that only existed on your machine. Every developer has lived this, and for decades it was just accepted friction. Containers are the technology that finally killed it. This chapter is about the problem they solve and what a container actually is — before you run a single command. It builds directly on the Linux fundamentals from the previous guide: a container is, at heart, a very cleverly isolated Linux process.
The problem, in three words
"Works on my machine." It's a joke, a meme, and a genuine source of lost hours across the whole industry. Here's why it happens.
Your program almost never runs alone. It depends on a whole environment around it: a specific version of a language runtime (Python 3.11, Node 20), a pile of libraries, some system tools, environment variables, configuration files. On your laptop, all of that is present and at the right versions — you installed it over months without noticing. The code runs because its environment happens to be correct.
Move that same code to a different machine and the environment is different. The server has Python 3.9, not 3.11. A library is missing, or a version too old. A config file lives somewhere else. The code is identical; the environment isn't — and so it breaks. Multiply that across a team, a fleet of servers, and years of accumulated setup, and "get this app running somewhere new" becomes a genuinely hard problem.
What a container actually is
A container is your application running inside its own isolated, self-contained bubble — bundled with every dependency it needs, sealed off from the machine around it. Inside that bubble, the app sees its own filesystem, its own installed libraries, its own view of the system. It doesn't know or care what's installed on the host.
The crucial consequence: because the container carries its entire environment with it, that environment is identical no matter where the container runs. Your laptop, a teammate's, a test server, production in the cloud — the container brings its own Python 3.11, its own libraries, its own everything. The host's setup becomes irrelevant. "Works on my machine" dies because the machine no longer decides what the app sees; the container does.
If you read the Linux guide, here's the honest technical picture: a container is really just a normal Linux process that the kernel has been told to isolate — give it its own filesystem view, its own process list, its own network, and limits on what it can see and use. There's no magic and no emulated hardware. It's your program, running directly on the host's Linux kernel, inside walls the kernel enforces. That's why containers are so light — which is the next, decisive idea.
Containers vs virtual machines
If you've heard of virtual machines (VMs), containers can sound similar — both "isolate" software. But they work in fundamentally different ways, and the difference is the whole reason containers took over.
A virtual machine emulates an entire computer. On top of your real hardware sits a layer (the hypervisor) that pretends to be a full physical machine, and inside it you install a complete guest operating system — its own kernel, its own everything — and then your app on top of that. It's genuinely a computer within a computer.
A container shares the host's operating system kernel instead of bringing its own. It packages only the layer above the kernel — your app, its libraries, its files — and relies on the host's Linux kernel to actually run. There's no guest OS, no emulated hardware.
VIRTUAL MACHINES CONTAINERS
[ App A ] [ App B ] [ App A ] [ App B ] [ App C ]
[ Libs ] [ Libs ] [ Libs ] [ Libs ] [ Libs ]
[Guest OS][Guest OS] [───── Docker engine ─────]
[─── Hypervisor ──] [──── Host OS kernel ───]
[──── Host OS ────] [────── Hardware ───────]
[─── Hardware ────]That single architectural difference — emulate a whole OS versus share the host's kernel — cascades into every practical advantage:
- Size. A VM image carries an entire operating system: gigabytes. A container image carries only the app and its libraries: often tens of megabytes.
- Speed. Booting a VM means booting a whole OS — tens of seconds. Starting a container is just starting a process — milliseconds.
- Density. Because each container is so light, one machine can comfortably run dozens or hundreds of them. VMs, carrying a full OS each, are far heavier per unit.
Why Docker, specifically
Here's a surprise: the kernel features that make containers possible existed in Linux for years before anyone was talking about "containers." They were powerful but fiendishly hard to use — a tangle of low-level tools that only kernel experts touched. The technology was there; the usability wasn't.
Docker, launched in 2013, changed exactly that. It didn't invent containers — it made them easy. Docker wrapped those gnarly kernel features in a simple, consistent set of commands (docker build, docker run) and, crucially, a standard format for packaging an app into a shareable unit called an image (the whole of the next chapter). Suddenly any developer could build a container, run it, and hand it to someone else who could run the exact same thing. That leap in usability is why containers went from obscure infrastructure trick to the foundation of modern software in just a few years.
- Pre-2013The raw ingredients exist
The Linux kernel gains the isolation features (namespaces, cgroups) that make containers possible — but using them directly is complex and reserved for experts.
- 2013Docker arrives
Docker wraps those kernel features in simple commands and a standard image format. Building and sharing a container becomes something any developer can do in minutes.
- 2015+Orchestration
As teams run thousands of containers, tools like Kubernetes emerge to schedule, scale, and heal them automatically. Containers become the unit of deployment.
- TodayThe industry standard
Cloud platforms, CI/CD pipelines, and microservice architectures all assume containers. Shipping software largely means shipping container images.
Why this is foundational
Containers aren't a niche tool you might reach for occasionally — they're the substrate that modern software delivery runs on. When you deploy to a cloud platform, you're almost always shipping a container. When a continuous-integration pipeline runs your tests, it does so inside a container for a clean, identical environment every time. Microservices — dozens of small apps making up one system — are packaged as containers. And Kubernetes, the technology orchestrating much of the internet's infrastructure, exists specifically to run containers at scale.
Underneath all of it sits the plain idea from this chapter: package the app with its environment, so it runs the same everywhere. In the rest of this guide we'll make that concrete. Next up is the pair of ideas at the very centre of Docker — the image (the packaged blueprint) and the container (a running instance of it) — and why keeping them straight makes everything else click into place.