Docker is weird
419 points - yesterday at 11:45 PM
SourceComments
I'm happy to answer any questions you may have.
My bash build scripts looked like Dockerfiles.
Most of the container code in Linux came from those russian guys.
Took me 6 months to find out the difference between stateless and stateful containers, after Jerome Petazzoni published a blog post opposing the usage of an SSH server inside containers.
What made Docker unique were there things:
1. Dockerfile concept. Building images layer by layer. Caching layers. Everything in a single file. It made possible to iterate on image quickly. It made possible to implement CI builds efficiently.
2. Docker network registry concept. Putting universal images onto a server and share them with the world.
3. Momentum. A lot of software that was traditionally complicated to deploy, suddenly appeared in docker servers. I remember how fascinated I was, when I could deploy wordpress website with tiny docker-compose. And how contained it was. I could just delete every trace of it from my host. I always felt uneasy installing various things onto my host and docker just solved that uneasiness.
I worked at Docker from 2014-2019. The most important part is actually written in C.
[I wrote a whole comment here about to explain how the hack works because I was too fixated on how technically incorrect "written in Go" is. Then I went back to read the rest of the article only to see that the paragraph immediately after this kind of explains it in its own way! Let that be a lesson to always finish reading the article before posting about it.]
- Today, a lot of functionality still in Docker has been upstreamed into the (Linux) kernel, so containers can be much simpler (and rootless). Docker is still carrying around some of that cruft, which is what makes it slower and heavier than Podman.
- As a devex technology, Docker/containers have been massively successful, but not as infrastructure. Containers never became secure enough to run multitenant workloads without some other form of isolation, so they ended up being redundant with KVM (or gVisor, or a similar second layer) in production a lot of the time.
That second contradiction led to lots of inefficiency. For example, on Google App Engine, for years when you ran a deploy it would create a VM just to run a single container.
Knowing this, you might find rootless Podman's fork-exec method of starting containers to be more sensible. I certainly do. No root, no daemon, no socket.
If you want to learn more about the Linux Kernel namespaces which work together to make a container, this LWN series is really good: https://lwn.net/Articles/531114/
It turns out you can do all the packet processing magic (connection tracking, syn handling, etc) in userspace totally fine, and then indeed hand it over this to userspace syscalls.
Being upset with classic C-based slirp and rust smoltcp (not enough features) I've dug up Fuchsia userspace tcp/ip stack - netstack - and wrapped it in slirp a-like envelope.
https://github.com/cloudflare/slirpnetstack
So this beast is basically that - on one hand you pass it packets (potentially from inside container) on the other hand it does connect/bind/etc to host OS.
This approach, in one form or another, is used by tailscale, podman and many other container runtimes.
Everything in that list feel natural when you know how things evolves over many years. Maybe it is just me getting older and less curious.
[1] "Docker implemented in around 100 lines of bash" https://github.com/p8952/bocker
Though it would be better if it compared Dockers ways to say Podman, which does things a little different I think.
For others, like me:
Footgun:
A footgun is a programming or system design term for a feature, tool, or API that makes it very easy for a user or developer to shoot themselves in the foot—meaning it causes self-inflicted damage or severe errors while working exactly as intended.
Try to make your own VM runtime next, you might be surprised!
One of the gnarliest issues I recall was where network namespaces could occasionally not be cleaned up correctly. So "randomly" (but more likely under certain loads) the networking of a reused thread would get jacked and Docker could no longer pull images.
Containers From Scratch • Liz Rice • GOTO 2018
A few cool tricks:
`range shell python:3.12` - opens a shell image without pulling the entire image.
`range shell ubuntu --commands` - you are in Ubuntu. Type any command Ubuntu doesn't have and it comes from the image that has it. On the fly.
`range run --network none ubuntu` - network-isolated sandbox
range run ebs://snap-... -- cat /etc/os-release - opens an EBS snapshot with no EC2 instance
Another cool trick:
`range run python:3.12 --mount hf://moonshotai/Kimi-K2-Instruct:/model -- du -sh /model` says 959G instantly :)
Check it out here - https://getrange.sh
Most importantly, Range doesn't need any daemon, any container runtime, any registry or any image conversion. One binary only. On a Mac it boots its own tiny Linux VM per session, and on Linux it uses KVM.
This is very important for debugging! Not just that process, but the processes running in that Docker can be found in /proc.
Why this is useful is that you can run gdb outside of that docker and point it to a process in the docker, including setting the file system root to the docker one, so that it gdb reads the correct objects from the correct paths, to get the right symbols and addresses.
It's not a vm: It's all namespaces, baby! Unshare one or more of your mnt, pid, net, ipc, uts, user, cgroup, or time namespaces and you have a "container".
I love Go and use it for everything I can but will absolutely concede this point. It's clearly possible to write the most successful container runtimes on earth in Go, but you absolutely have to fight the language/runtime sometimes. Since containers are based on processes, handing off a container spec to a minimal rust runtime seems like what we should all be doing by now. crun has just proven good enough that AFAIK no one has RIIR.
And implying the system kernel still has to run the container kinda ignores kata containers and gvisor runtimes.
Side note almost nothing about Docker is weird. This article chooses rather boring design decisions and picks on them.
> Did you know that databases are just a file?
oOoOoOoOo
Mostly joking. It's cool to see tech demystified, but I feel like a lot of things we use and take for granted are like this.
"It's an idempotent language for OS level dependencies so you can be sure exactly what is running on your server"
Gimme gimme gimme!
Other weird facts about OSes: a filesystem is a database, the Linux kernel is a monolithic program, "hidden" dot-files were a Unix bug that got carried forward, deleting a file doesn't remove the file from your machine, virtual memory is a lie, your computer can't run multiple programs at once (it's just running one at a time real fast), in 12 years most systems will crash due to one number getting too big, you technically never need to reboot because you can launch a different version of Linux while already running Linux, you can freeze a program to a file and then later resume running that same program in the same state (but nobody uses it), files aren't actually stored in directories, there's a maximum number of files (and size of file) on most filesystems (which you can use to lock up a machine, despite file quotas existing and nobody using them), you can lock up most systems by forking too many times / using too much RAM / accessing disk too much, there's a default number of open files and/or TCP ports which is artificially low and you can use to again lock up a machine, pipes are just two file descriptors connected to one memory buffer, an IP address is just one long number split up into bytes, etc.
This is not a slight on Docker itself. It’s a slight on the conditions that induced Docker to exist.
One of the great selling points of one of my projects is “this is easy to run without needing Docker”.
And folders are graphical representations of directories--sometimes, not always--and not directories themselves. When will the newbies get this?