The Invoice ■ Episode 08
“Ship the entire operating system with your application, because the operating system could not agree on how to install one.”
That is the pitch, stripped of its marketing. Docker did not arrive because
the technology was missing (process isolation had existed since 1979).
Docker arrived because Linux fragmented so thoroughly that deploying a binary
across distributions became an exercise in diplomatic negotiation. The industry
did not solve the fragmentation. It surrendered to it, wrapped the surrender
in a Dockerfile, and called it innovation.
The Fragmentation
Linux is not one operating system. It is a kernel with opinions:
hundreds of them, organised into distributions that agree on remarkably little.
apt or pacman or dnf or apk.
systemd or
OpenRC or runit. glibc or musl.
/usr/lib or /usr/lib64. Configuration in
/etc, except when it is in /usr/share, except when
it is compiled in, except when a flag changes everything.
A binary compiled on Debian may not run on Alpine. A service file written for systemd is meaningless on Void. A package built for Fedora requires a different set of shared libraries than the same package on Ubuntu, despite both claiming to be Linux.
This is not a bug. This is the culture, a community that values choice over coherence, which is a perfectly respectable philosophical position right up until the moment you need to ship software to someone else’s machine.
The Surrender
Docker’s solution to Linux fragmentation was not to fix it. It was to bypass it entirely. Ship the entire userland (libraries, tools, init scripts, the lot) bundled alongside your application. The host kernel provides isolation. Everything above the kernel comes in the image.
A 28 MB Node.js runtime becomes a 1.1 GB container image because the image includes Debian. Not because Debian is needed. Because the alternative, trusting the host to provide a consistent environment, had been tried and found wanting. Docker is what happens when an ecosystem gives up on compatibility and decides that duplication is cheaper than coordination.
The elegant irony: Docker replaced distribution fragmentation with
base image fragmentation. FROM debian:bookworm or
FROM alpine:3.19 or FROM ubuntu:24.04. The same
incompatibilities, the same library mismatches, the same arguments about
glibc versus musl, now happening inside the container instead of
outside it. The boundary moved. The problem did not.
The Three-OS Problem
Docker uses Linux kernel features (namespaces and cgroups) that exist nowhere else. On a Linux server, this is seamless. The container shares the host kernel. Overhead is negligible.
On macOS and Windows, Docker cannot run natively. It requires a Linux virtual machine. Docker Desktop on a Mac means: macOS runs a hypervisor, the hypervisor runs Linux, Linux runs the Docker engine, the Docker engine runs the container image, which contains another Linux distribution. Four layers. Three operating systems. Roughly 4 GB of RAM reserved before a single container starts.
The word “portable” does rather a lot of work in the Docker documentation. What it means, precisely, is: portable between Linux kernels. Everywhere else, it is virtualisation wearing the costume of containerisation. The performance penalty (bind mounts 2.5 times slower, I/O crossing a VM boundary, RAM consumed by a guest OS that exists solely to run the tool that was supposed to simplify things) is the cover charge for the illusion.
The Prior Art
The technology Docker is credited with popularising was not new. It was not even particularly young. The timeline is instructive:
FreeBSD Jails
shipped in March 2000: full process isolation, separate networking stacks,
independent filesystems. Solaris Zones followed in 2005 with resource controls
and ZFS integration. LXC arrived in 2008 and became Docker’s original
backend before Docker replaced it with libcontainer in 2014.
Docker’s contribution was not the container. It was the image format,
the registry, and, critically, the narrative. A five-minute
lightning talk at PyCon 2013, a company that understood developer experience
better than any Unix vendor before it, and an industry that was tired of
fighting with apt-get on twelve different distributions. The
technology was thirty-four years old. The marketing was new.
The FreeBSD Contrast
The comparison is illuminating not because FreeBSD is perfect, but because it demonstrates what happens when a project chooses coherence over choice.
FreeBSD has one base system. One package manager: pkg. One
init system: rc. One libc. Packages compiled for FreeBSD 14
run on any FreeBSD 14 installation, because there is only one
FreeBSD 14. There are no distributions. There is no fragmentation. A binary
built on one machine runs on every machine with the same major version.
Jails provide isolation that is native, lightweight, and requires no virtualisation on any platform FreeBSD supports. No hypervisor. No guest OS. No 4 GB of RAM sacrificed to the abstraction. A jail starts in milliseconds and shares the host kernel directly, because the host kernel was designed for it, not retrofitted with it.
This is not a philosophical preference. It is an engineering decision with measurable consequences. When your base system is coherent, you do not need to ship the entire OS alongside your application. You ship the application. The operating system is already there, and it is the same everywhere.
The Invoice
The monetary costs are well-documented, if seldom totalled.
Docker Desktop: free for personal use, €9 per user per month for teams, €21 per user per month for business. For a company of 250 developers (the threshold at which Docker Desktop requires a paid subscription), the annual bill starts at €27,000 and climbs to €63,000. For the privilege of running a Linux VM on hardware that does not need one.
Image sizes compound the cost. A typical microservices deployment pulls dozens of images, each carrying its own copy of an operating system. Registry storage, network transfer, CI build minutes, layer cache invalidation: all of it scales with the bloat. Two gigabytes per image is not unusual. The bandwidth bill for pulling fresh images across a fleet is the line item nobody audits until it appears on the quarterly report.
And then there are the CVEs. A base image frozen in a Dockerfile
does not update itself. Every unpatched library in that image is a vulnerability
that persists until someone rebuilds the image, pushes it to the registry, and
redeploys. The mean time between “CVE published” and
“container actually patched” is, in most organisations, measured
in weeks. In some, it is measured in the passive voice: “it will be
addressed.”
The Verdict
Docker is a useful tool. It solved a real deployment problem on Linux servers
and solved it well. The Dockerfile format is elegant. The
registry model is sound. The developer experience was, for its era,
genuinely excellent.
But the problem it solved was not a technology problem. It was a politics problem. Linux distributions could not agree on a base system, a package format, an init system, or a C library. Rather than fix the fragmentation, the industry accepted it and built a workaround that ships the entire operating system alongside every application.
On macOS and Windows, where the majority of developers actually work, that workaround requires a virtual machine, consuming gigabytes of RAM to simulate the operating system whose fragmentation created the need for the tool in the first place. The recursion is almost poetic.
Docker did not solve a technical problem. It monetised a political one. The technology had existed since 1979. The fragmentation had existed since the first Linux distribution fork. Docker packaged the capitulation into a product, gave it a whale logo, and sold it back to the engineers whose ecosystem created the problem.
FreeBSD has one base system. Packages work everywhere. Jails have provided isolation since the year 2000. No VM required. No subscription fee. No whale.
The invoice is €27,000 to €63,000 per year, plus 4 GB of RAM per developer machine, plus 2 GB per image, plus the CVEs nobody patches, plus the I/O overhead nobody measures. All of it payable to a company whose product exists because an operating system could not agree with itself.
That is not engineering. That is capitulation with a subscription model.