Docker from First PrinciplesPost 2 of 18 · 18 of 18 written

2. What a container really is

Docker · 2 of 184 min readOct 2026

There is no “container” object in the Linux kernel. A container is an ordinary process that the kernel shows a restricted view of the world (namespaces), caps in resources (cgroups), roots in a different directory tree (the image’s filesystem), and strips of some privileges (capabilities, seccomp). Understand those four mechanisms and Docker stops being magic.

Start from processes

Every running program is a process: it has a PID, a user ID, open files, memory, and a view of the filesystem and network. Start docker run -d --name s alpine sleep 1000 on a Linux machine, then run ps aux | grep sleep on the host: the sleep process is right there, like any other. docker inspect -f '{{.State.Pid}}' s prints its host PID. On your Mac this happens inside Docker Desktop’s VM, which is why you don’t see it in Activity Monitor.

Namespaces: what a process can see

A namespace gives a process its own private copy of one kind of global resource. Docker puts each container in a fresh set of them.

Namespace What it isolates What you notice in practice
PID Process IDs The container’s main process sees itself as PID 1 and cannot see host processes
Mount Mount table The container has its own /, built from the image, plus its own mounts
Network Interfaces, IPs, routes, ports, localhost localhost inside a container means the container itself, not your machine
UTS Hostname The container’s hostname is its short ID unless you set one
IPC Shared memory, message queues Matters for /dev/shm, which PyTorch DataLoader workers use (Part 10)
User UID and GID mapping Can make root-in-container an unprivileged user outside; off by default in Docker
Cgroup The view of the cgroup tree The container sees its own limits as the root of the tree

You can see a process’s namespaces with ls -l /proc/<pid>/ns or lsns. The most common beginner bug comes straight from the network namespace: a server bound to 127.0.0.1 inside a container is unreachable from outside it, because that loopback belongs to the container alone.

Control groups: what a process can use

Cgroups limit and account for CPU, memory, number of processes and disk I/O. --memory 8g writes a memory limit into the container’s cgroup; if the process exceeds it, the kernel’s OOM killer kills it, and Docker reports exit code 137 with OOMKilled: true. --cpus 4 sets a CPU-time quota. Without flags, a container can use the whole machine.

One ML-relevant trap: limits are enforced, but not always visible. Python’s os.cpu_count() inside a container limited with --cpus 4 still reports every host core, so PyTorch, NumPy or a DataLoader may start far more threads than the quota allows and run slower. Set OMP_NUM_THREADS, MKL_NUM_THREADS or torch.set_num_threads() explicitly. Modern Linux distributions use cgroup v2, a single unified hierarchy; older guides describe v1.

The root filesystem

When the container starts, its process gets the image’s filesystem as / (Docker uses pivot_root, a stronger cousin of chroot). That’s why an Ubuntu-based container has apt and an /etc/os-release saying Ubuntu, even on a Fedora host. But run uname -r inside it and you get the host’s kernel version: the user space came from the image, the kernel did not.

Privilege restrictions on top

  • Capabilities split root’s powers into about 40 separate rights. Docker gives containers only a small default set; for example, changing network configuration (CAP_NET_ADMIN) or broad system administration (CAP_SYS_ADMIN) is withheld.
  • seccomp filters which system calls a process may make. Docker’s default profile blocks dozens of rarely needed, risky calls.
  • AppArmor or SELinux add mandatory access rules on hosts that use them.
  • --privileged turns most of this off and gives the container nearly full access to the host’s devices. Treat it as a red flag in any instructions you copy.

Containers versus virtual machines

Aspect Container Virtual machine
Kernel Shares the host kernel Runs its own guest kernel
Start time Milliseconds to seconds: just a process start Seconds to minutes: an OS boot
Size Megabytes to a few gigabytes Gigabytes of disk image
Isolation strength Process-level; a kernel bug can break it Hardware-level; much harder to escape
GPU access Device files passed in, near-native speed PCI passthrough or vGPU, more setup
Other operating systems Linux containers need a Linux kernel Any OS the hypervisor supports

This table explains Docker Desktop: macOS has no Linux kernel, so Docker Desktop runs a small Linux VM and your containers live inside it. Part 13 covers microVMs such as Firecracker and gVisor, which blur the line when you need VM-like isolation with container-like speed.