HomeTechHow Docker Containers Actually Work Under the Hood: Namespaces, Cgroups, and UnionFS
Tech

How Docker Containers Actually Work Under the Hood: Namespaces, Cgroups, and UnionFS

Containers are not lightweight virtual machines. They are isolated Linux processes governed by kernel namespaces, control groups (cgroups), and layered copy-on-write...

Think Hollow Editorial
Senior Research & Publishing Fellow
Oct 24, 2026•6 min read (1,094 words)
How Docker Containers Actually Work Under the Hood: Namespaces, Cgroups, and UnionFS

#1. The Virtual Machine Fallacy: What a Container Really Is

The most common mental model taught to new engineers is that 'containers are lightweight virtual machines.' While useful as an introductory analogy, this framing is technically incorrect and obscures the true elegance of modern container runtimes.

In a traditional Type-2 Hypervisor architecture (such as VMware ESXi, VirtualBox, or KVM), a physical host runs a hypervisor that emulates virtual hardware - virtual CPUs, BIOS, memory controllers, and network interface cards. Inside this emulated sandbox, a complete guest operating system kernel must be loaded into memory, carrying its own kernel schedule, systemd initialization, device drivers, and background daemons. This introduces tens of gigabytes of disk overhead, minutes of boot latency, and 5% to 15% CPU virtualization penalties.

A Docker container, by contrast, has no guest kernel, no hypervisor, and no virtualized hardware. When you launch a container, you are executing a standard native Linux process on the host kernel. What makes it a 'container' is that the kernel applies three fundamental isolation features: Linux Namespaces, Control Groups (cgroups), and Layered Union Filesystems.

#2. Linux Namespaces: The Illusion of Isolation

Linux Namespaces, first introduced in kernel 2.4.19 and expanded throughout the 2000s, partition kernel resources such that one set of processes sees one set of resources while another set sees a completely different view.

Docker orchestrates six primary kernel namespaces to construct a container jail:

1. PID Namespace (Process IDs): Inside the container, your application process believes it is Process ID 1 (PID 1), the root of the init process tree. On the host operating system, however, the kernel views that exact same process as an unprivileged process with a standard PID like 14285.

2. NET Namespace (Networking): Isolates network interface controllers, routing tables, firewall rules, and port bindings. This allows five distinct containers on the same physical host to all bind to port 80 simultaneously without port collisions, communicating via a virtual bridge (docker0) and veth pair cables.

3. MNT Namespace (Mounts): Isolates the filesystem mount table. The container process sees only the root directory (`/`) provided by its container image, completely blind to the host's `/etc`, `/var`, or `/home` directories unless explicitly mounted via volumes.

4. UTS Namespace (Hostnames): Allows the container to have its own unique hostname and domain name.

5. IPC Namespace (Inter-Process Communication): Prevents containers from accessing shared POSIX memory segments or message queues of other processes.

6. USER Namespace: Maps the container's root user (UID 0) to an unprivileged standard user (UID 10001) on the host, preventing container breakout attacks from compromising host root privileges.

#3. Control Groups (Cgroups): Resource Governors

While namespaces dictate what a process can *see*, Control Groups (cgroups) - developed primarily by Google engineers in 2006 - dictate how much physical hardware a process can *consume*.

Without cgroups, a single runaway memory leak or crypto-mining exploit inside a container could consume 100% of the host's CPU and RAM, triggering the Linux kernel's Out-Of-Memory (OOM) killer to terminate vital host services.

Under cgroups v2, the kernel enforces fine-grained resource accounting:

- CPU Bandwidth: Using the Completely Fair Scheduler (CFS), cgroups allocate CPU quota in microseconds (e.g. `cpu.cfs_quota_us = 50000` against a 100000 microsecond period restricts the container to exactly 0.5 CPU cores).

- Memory Limits: Sets hard thresholds (`memory.max`). If a container exceeds this boundary, the kernel's OOM killer isolates and terminates the offending container process without degrading other host workloads.

- Block I/O: Throttles read and write disk IOPS to prevent intensive database writes from bottlenecking overall server disk performance.

#4. Layered Filesystems: The Magic of OverlayFS and Copy-on-Write

If a container image weighs 500 megabytes, launching 100 instances of that image should theoretically consume 50 gigabytes of disk space and take minutes to copy. In Docker, 100 containers launch in milliseconds and consume virtually zero additional storage.

This efficiency is achieved through Union Mounts, specifically OverlayFS. A container image is stored as an immutable stack of read-only layers (`lowerdir`). Each `Dockerfile` instruction (`RUN`, `COPY`, `ADD`) creates a static cryptographic hash layer containing only the diff of files added or modified in that step.

When a container starts, Docker creates a thin, ephemeral writable layer (`upperdir`) on top of the image stack, presenting them as a single unified directory (`merged`).

When the container reads a file, it reads directly from the shared lower layer. When it modifies a file, OverlayFS performs a 'copy-on-write' (CoW) operation: copying the original file up into the writable layer before editing. 100 running containers share the exact same 500 MB base image in memory and on disk, writing only their small runtime diffs.

#5. The OCI Standard: runc and Containerd

Modern Docker is not a monolithic binary. In 2015, Docker donated its core runtime specifications to the Open Container Initiative (OCI).

Today, Docker delegates lifecycle management to `containerd`, which calls `runc` - a lightweight CLI tool that issues the low-level Linux syscalls (`clone`, `unshare`, `setns`, `pivot_root`) to configure the namespaces and cgroups.

Because Kubernetes and Docker adhere to the OCI runtime standard, containerized applications are 100% portable across any modern Linux cloud environment.

In-Depth FAQ

Frequently Asked Questions

Common inquiries, counterarguments, and technical details explored.

Q

Can you run Docker containers natively on Windows or macOS?

Not natively. Because containers rely directly on Linux kernel features (namespaces and cgroups), Docker Desktop on macOS and Windows transparently runs a lightweight Linux virtual machine (Hyper-V, WSL2, or Apple Virtualization Framework) in the background to host the Linux kernel.

Q

What is the difference between an image and a container?

An image is an immutable, read-only template built from layered filesystems and metadata. A container is an active running instance of that image with an ephemeral writable layer and dedicated namespace/cgroup boundaries.

Q

Can a container break out and compromise the host?

Container breakouts are rare but possible if containers run with the `--privileged` flag, share the host PID namespace, or exploit unpatched Linux kernel vulnerabilities (such as Dirty COW). Running containers with rootless mode and dropped capabilities (`--cap-drop=ALL`) provides robust defense-in-depth.

B

Written by Think Hollow Editorial

The BlankVerse editorial team publishes deeply researched, peer-reviewed explainers spanning scientific breakthroughs, advanced technology, human cognitive biology, and cinema history.

Peer-Reviewed Evergreen Publication • Verified Knowledge
Share Article
Continue Reading

More in Tech

View All