What Is Docker, and What It Silently Replaced š¤«..
View original- current
Summary (TL;DR)
Docker replaced manual deployment practices like runbooks and snowflake servers by packaging applications with their dependencies into portable images. Before Docker, environment mismatches between developer laptops and production caused outages, exemplified by Knight Capital's $460 million loss in 2012. Docker uses Linux namespaces and cgroups to isolate processes, but its key innovations were the image format and registry. A simple Dockerfile codifies runtime, dependencies, and startup commands, eliminating human errors. Docker didn't solve multi-machine orchestration (Kubernetes filled that) or fix bad code, but it made deployments reproducible. The industry shifted from tools like Chef and Puppet to containers.
What Is Docker, and What It Quietly Replaced
Before containers, deployment was a personās job. The person is gone now.
5 days ago
The website is down at 2 AM on a Tuesday. Your manager is on the phone with the VP of Engineering. The VP is on the phone with a client. It's on your ass to solve the actual issue while everyone else just talks.
You SSH into the production server. The deployed code depends on a system library the team forgot to install. You run apt-get install libxml2-dev.
š±š±
There was no deploy script but a wiki page titled āRelease Steps (UPDATED IN FEB, DO NOT SKIP STEP 14)ā built by the first engineer who left after giving you a comprehensive 23 seconds handover and a pat in the back. The engineer was so caring that printed it and taped to the wall near the server racks without telling you.
Believe it or not, that was what deployment looked like for most of the 2000s.
If you started writing software after 2015, you missed it all.
Year 2000 - A physical server rack with a series of notes for the next unlucky who sees it: UPDATED IN FEB, DO NOT SKIP STEP 14.
The phrase āworks on my machineā is a joke now. Jeff Atwood designed the certification badge in 2007. It was not a joke then, it was the root cause of outages that cost people their jobs, and sometimes their companies.
In August 2012, Knight Capital deployed new trading software to eight servers. The deploy reached only seven. The eighth ran dormant code from 2003. In 45 minutes, that one server generated over $460 million in losses. The failure was in the deployment, not in the code.
What happened?
A developer tested on their laptop and then they handed the code to an ops team. The ops team spent hours on it. The application refused to start, and the reason was unclear.
The answer, almost every time: something was different. A different version of Python. A missing environment variable. A config file that lived in /etc/ on one machine and /opt/ on another.
The gap between a developerās laptop and a production server was an organizational problem, not developer incompetence. Two groups of people maintained two different environments with two different sets of assumptions. They discovered the mismatch at deploy time, in front of customers.
Docker helped to close that gap.
The way it closed it matters. Docker did not just give developers a new tool. It made a set of human practices unnecessary, and those practices had names, roles, and careers attached to them.
The gap between a developerās laptop and a production server is an organizational problem, not developer incompetence.
Teams used to write deployment runbooks by hand: step-by-step documents describing how to put software onto a server. They went stale within weeks. Step 7 assumed you had already run a command from a different runbook and few people that ran through the whole thing start to finish got a clean result.
Then there were the servers themselves.
Martin Fowler gave the pattern a name in 2012: snowflake servers. These were production machines configured by hand over months or years. No two were identical. Each had its own installed packages, patched libraries, and undocumented tweaks applied during outages months ago.
You lost one, you did not rebuild it. You nursed it. Bill Baker at Microsoft had a phrase for it: pets versus cattle. Some teams took the pet side literally, giving their servers human names. Losing one was painful and personal.
I once worked on a team with a server called ādavros.ā It ran a version of Nginx older than anything in the standard package managers. Upgrading it meant risking the production SSL config. Only one person understood that config and they had left the company.
So davros stayed. For years.
The release engineer knew which servers had which versions of Java. They knew that server 3 needed a restart after every deploy. A memory leak caused it. The team had no time to fix it.
Davros ran a version of Nginx older than the depreciation lifecycle of the hardware it was running on.
Docker arrived, and CI/CD pipelines absorbed most of this roleās daily work. The title still exists at larger companies. Googleās SRE book defines it as a distinct function. The work inside it changed completely.
Chef and Puppet tried to solve the snowflake problem with code. You described a serverās target state, and the tool enforced it. A Chef cookbook for a Rails app ran to hundreds of lines. Debugging it required understanding both the application and the configuration tool.
Docker collapsed their commercial relevance for application deployment. The acquisition wave tells the story: Ansible to Red Hat in 2015, Chef to Progress Software in 2020, Puppet to Perforce in 2022, its IPO plans abandoned.
WTF is Docker?
A Docker container is a process running on a Linux machine with restricted visibility. It can only see its own filesystem, its own network interfaces, and its own process list.
The underlying kernel features existed for years. Linux namespaces date to around 2002. Cgroups, started by Google engineers Paul Menage and Rohit Seth, merged into the kernel in January 2008. LXC containers used the same primitives. Early Docker was a wrapper around LXC.
Solomon Hykes demoed Docker at PyCon on March 15, 2013. His innovation was not the container. It was the image format, the registry, and the developer workflow around them.
A Docker image is a snapshot of a filesystem. It contains the operating system, the runtime, the libraries, and the application code in a single file. You build it once. Then you copy it to any machine that runs Docker. It starts the same way on each one.
Here is what a simple Dockerfile looks like:
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]Each line codifies something a human used to do by hand. FROM node:20-alpine locks the runtime to Node.js version 20. COPY package*.json and RUN npm ci install the dependencies the developer tested against, not whatever version the server happened to have.
The interesting lines are further down:
EXPOSE 3000documents the port the app listens on. Opening that port in a firewall used to require a ticket to the networking team.CMDsets the start command. The ops team no longer needed to ask the developer "how do I run this thing."
Seven lines. That replaced a runbook, a release engineer, and a wiki page with 14 steps.
Docker opened its public registry in May 2013. It became Docker Hub at the first DockerCon in June 2014. You push an image once. You can pull it anywhere.
Docker turned deployment from an installation into a copy.
That image format later became a formal standard. Docker, CoreOS, and others founded the Open Container Initiative in June 2015 to formalize it. Environment mismatch, missing dependencies, version conflicts, undocumented server state: all of these collapsed into one category. They became the image authorās problem, solved once at build time.
Docker didn't replace everything.
Docker runs a single process in an isolated environment. It does not handle what happens across multiple machines or after a crash.
Google announced Kubernetes in June 2014 to fill that gap. Docker solved the single-machine problem and left the multi-machine problem untouched. Orchestration, service discovery, load balancing, secret management: these are problems that live above the container layer.
Docker did not replace the need to understand what runs inside the container. Some teams treated images as opaque boxes. They found debugging got harder, not easier. You trade filesystem access for reproducibility. The tradeoff is real.
And, of course, Docker did not fix bad software. A container that packages a memory-leaking application produces a memory-leaking container. The isolation is clean but the code inside it is still yours and you can fuck it up like everything else.
Docker solved the single-machine problem and left the multi-machine problem untouched
The ecosystem partly displaced Dockerās own runtime. Kubernetes dropped Dockerās container shim in favor of containerd, a component Docker itself had donated. The format outlived the companyās control over it.
Davros is gone but the hard part remains: you still have to write software that works.
Docker just made sure āworksā means the same thing in every environment.
If you liked this, you might like readplace.com, built for exactly this kind of reading.
Thanks for reading. If you have some feedback, reach out to me on LinkedIn, Reddit or by replying to this post.