AV
HomeAboutProjectBlog

© 2026 Ave syah Shina. All rights reserved.

  1. Home
  2. Blog
  3. 02 — Underlying Technologies: How the Kernel Actually Makes a Container

02 — Underlying Technologies: How the Kernel Actually Makes a Container

August 13, 20268 min read
Download as Markdown

"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

namespaces — what it can see PID · NET · MNT · UTS · IPC · USER container process one ordinary PID on the host cgroups — what it can use CPU · memory I/O · device access union filesystem what its files are writable read-only layers

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-app

Those 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!