Free — no signup required

Putting It Together: How Docker Uses All Three

2 min read

From Primitives to Platform

When you run docker run -m 512m --cpus 0.5 ubuntu bash, Docker performs a precise sequence of kernel operations using all three mechanisms we have covered:

1. Namespaces — create isolation:
Docker calls clone() with flags for PID, NET, MNT, UTS, IPC, and USER namespaces. The new process starts in a completely isolated environment: its own PID space (it is PID 1), its own network stack (with a veth pair connected to the Docker bridge), and its own filesystem root (the Ubuntu image layers, assembled via overlay filesystem).

2. Cgroups — enforce limits:
Docker creates a new cgroup under /sys/fs/cgroup/docker/<container-id>/ and writes the memory limit (memory.max, in bytes — 536870912 for 512 MB) and CPU quota (cpu.max, expressed as microseconds of CPU time allowed per 100ms period — 50000 100000 for 50% of one core) into the cgroup's control files. The container's process is added to this cgroup. The kernel now enforces these limits automatically.

3. ulimit — set per-process defaults:
Docker sets nofile limits on the container process (default: 1048576 in modern Docker). You can override this with docker run --ulimit nofile=65535:65535.

The result: A process that believes it is alone on a machine with its own network and filesystem, but is actually constrained to exactly 512 MB of RAM and half a CPU core, running alongside hundreds of other such processes on the same physical host.

This is also why container "escapes" are serious security vulnerabilities — they involve breaking out of one or more of these namespace boundaries to gain visibility into or control over the host or other containers.

This is one of 18 chapters

Every chapter is free — Kubernetes, Terraform, SRE, distributed systems, and more — with fast daily review built in.

Sign up free