02 — Underlying Technologies: How the Kernel Actually Makes a Container
"Container magic" was the black box I blamed whenever Docker behavior surprised me. Writing it down dissolved the magic into three ordinary Linux kernel features, and the model that clicked is almost disappointingly simple: a container is an ordinary process that the kernel has wrapped with namespaces (what it can see), cgroups (what it can use), and a union filesystem (what its files are). [1][2]
The framing worth holding onto is that Docker invented almost none of this. Namespaces, cgroups, and union filesystems all existed in Linux for years before Docker shipped in 2013 [2][3]. What Docker did was package them into one pleasant tool — docker run — so I never have to think about the kernel plumbing. But every now and then a container misbehaves in a way that only makes sense if I remember what's actually happening underneath, so I wrote the plumbing down.
The three primitives at a glance
Three concerns, three kernel features. Each one answers a different question the kernel has to resolve for an isolated process [1][2][5].
Namespaces: what the process can see
A namespace wraps a global system resource so that a process inside it sees its own private instance of that resource [4]. The kernel maintains separate namespace "rooms," and a process placed in a set of them simply cannot see the resources in the host's or other containers' rooms. Docker leans on six of them:
- PID — the process sees itself as PID 1, blind to other processes on the host.
- NET — its own network stack: loopback, interfaces, routing table, ports.
- MNT — its own mount tree, so the filesystem it sees can differ entirely from the host's.
- UTS — its own hostname and domain name.
- IPC — isolated inter-process communication (shared memory, semaphores).
- USER — a UID/GID mapping, so the process can think it's root inside while mapping to an unprivileged user outside [4].
The part that clicked: namespaces are purely about visibility. They don't limit how much CPU or memory a process can burn — they only hide things. Throttling is the next primitive's job.
cgroups: what the process can use
Control groups (cgroups) are the complementary feature — they limit and account for resources a group of processes can use [5]. Where namespaces hide, cgroups cap. Docker uses them to enforce the constraints I pass on the command line:
# cap this container at half a CPU and 512MB of RAM
docker run --cpus="0.5" --memory="512m" my-appThose two flags translate into writes to cgroup control files the kernel reads on every scheduling decision. cgroups cover CPU, memory, block I/O, network bandwidth, and device access, and they're the reason a runaway container can't take the whole host down — I told the kernel, in advance, the ceiling [5].
Together namespaces and cgroups are the full isolation story. A container is a process placed in a fresh set of namespaces and attached to a cgroup. Hide it, then cap it.
Union filesystems: what its files are
The third primitive answers a question that stumped me at first: how does Docker store images so efficiently, when a 900MB Python image and a 900MB Node image share 800MB of base layers? The answer is a union filesystem — a way to overlay multiple directories (called layers) into one virtual tree without copying anything [6][7].
Each line in a Dockerfile creates a new layer. Read a file and the union FS walks the stack top-down and returns the first match; write a file and it lands in the topmost writable layer. The read-only layers below are shared across every image and every container that descends from them, which is why pulling a second image built on node:20 barely downloads anything new — the shared layers are already on disk [1][6]. Common implementations include OverlayFS (the modern default), and historically AUFS, Btrfs, and ZFS [6][7][8][9].
This is also the root of the "ephemeral filesystem" behavior I'll cover in the persistence post: a container's writable layer is thrown away when the container is removed, because the layer was never meant to be the source of truth.
The Linux prerequisite skills
Before I could read any of this comfortably, I had to admit how much of Docker is "just Linux." The roadmap lists four prerequisite skills, and they all boil down to: containers run Linux processes, so I need to be literate in the environment those processes live in.
- Shell commands. ls, cd, ps, grep, find, cat — these are how I poke around inside a container with docker exec, and how I read what a RUN instruction in a Dockerfile is actually doing [10][11].
- Shell scripting. Dockerfile RUN lines and entrypoint scripts are shell. Variables, conditionals, and the difference between CMD and an entrypoint script all make more sense once I've written a little Bash [12][13].
- Package managers. Base images are Linux distros, so installing a dependency means apt-get (Debian/Ubuntu), dnf/yum (Fedora/RHEL), or apk (Alpine). Cleaning the package cache afterward is how I keep image size down [14][15].
- Users, groups, permissions. chmod, chown, and the USER instruction matter because containers run as root by default — a real security smell. Creating a non-root user and switching to it is the baseline hardening I now reach for automatically [16][17].
I list these together because they share one trait: none of them are Docker-specific. They're the cost of entry for working confidently with Linux processes, and a container is just a Linux process.
How I use this
The payoff shows up in debugging. When a container can't reach another service, I now know to suspect the NET namespace — is it on the same Docker network? When it gets OOM-killed, I check the cgroup memory limit, not the host's free RAM. When a "saved" file vanishes after a redeploy, I remember the union FS writable layer was discarded, and reach for a volume. Naming the primitive underneath the symptom is the whole reason I wrote this down — once I see namespaces, cgroups, and layers as separate knobs, most container mysteries collapse into "which of the three is misconfigured?"
References
[1] Docker, Inc., "Open Source Components — Underlying Technologies," docker.com, 2024. [Online]. Available: https://www.docker.com/resources/what-container/#underlying-technologies
[2] F. Turkal, "How does Docker actually work? The hard way: A technical deep diving," Medium, 2021. [Online]. Available: https://medium.com/@furkan.turkal/how-does-docker-actually-work-the-hard-way-a-technical-deep-diving-c5b8ea2f0422
[3] T. Oberleiter, "Containers — Namespaces, Cgroups and Overlay Filesystem," YouTube, 2022. [Video]. Available: https://www.youtube.com/watch?v=wJdDWc6zO4U
[4] Linux man-pages project, "namespaces(7) — overview of Linux namespaces," man7.org, 2024. [Online]. Available: https://man7.org/linux/man-pages/man7/namespaces.7.html
[5] Docker, Inc., "Control Groups," docker.com, 2024. [Online]. Available: https://www.docker.com/resources/what-container/#control-groups
[6] Linux Kernel Documentation, "OverlayFS," kernel.org, 2024. [Online]. Available: https://www.kernel.org/doc/html/latest/filesystems/overlayfs.html
[7] AUFS Project, "Advanced Multi-Layered Unification Filesystem," aufs.sourceforge.net. [Online]. Available: http://aufs.sourceforge.net/
[8] Btrfs Project, "Btrfs Documentation," btrfs.readthedocs.io, 2024. [Online]. Available: https://btrfs.readthedocs.io/en/stable/
[9] ZFS on Linux, "ZFS," zfsonlinux.org, 2024. [Online]. Available: https://zfsonlinux.org/
[10] freeCodeCamp, "The Linux Commands Handbook," freeCodeCamp, 2024. [Online]. Available: https://www.freecodecamp.org/news/the-linux-commands-handbook/
[11] Codecademy, "Shell Commands Every Developer Should Know," codecademy.com, 2024. [Online]. Available: https://www.codecademy.com/article/command-line-commands
[12] shellscript.sh, "Shell Scripting Tutorial," 2024. [Online]. Available: https://www.shellscript.sh/
[13] linuxconfig.org, "Bash Scripting Tutorial for Beginners," 2024. [Online]. Available: https://linuxconfig.org/bash-scripting-tutorial-for-beginners
[14] Ubuntu, "APT Package Management Guide," ubuntu.com, 2024. [Online]. Available: https://ubuntu.com/server/docs/package-management
[15] Alpine Linux, "Alpine Package Keeper (apk)," Alpine Wiki, 2024. [Online]. Available: https://wiki.alpinelinux.org/wiki/Alpine_Package_Keeper
[16] Red Hat, "Linux File Permissions Explained," redhat.com, 2022. [Online]. Available: https://www.redhat.com/en/blog/linux-file-permissions-explained
[17] Docker, Inc., "Dockerfile reference — USER," Docker Docs, 2024. [Online]. Available: https://docs.docker.com/reference/dockerfile/#user
Knowledge check · Question 1 of 5
Which kernel primitive answers the question "how much CPU and memory can this container use?"
Comments
Leave a Comment
You must be signed in to comment
0 Comments
No comments yet. Be the first to comment!