Docker is a wrapper. The kernel does the work.
It is tempting to think Docker invented containers. It did not. Linux namespaces shipped in 2002, cgroups in 2007, OverlayFS in 2014. Docker (2013) made these primitives usable — same way Git made Linus Torvalds's content-addressable storage usable.
The three pillars
1. Namespaces — what each process can see
Each container gets its own view of:
- PID — its own process tree (PID 1 inside is your app)
- NET — its own network stack (interfaces, routing, ports)
- MNT — its own filesystem mounts
- UTS — its own hostname
- IPC — its own shared-memory and semaphores
- USER — its own UID/GID mapping (rootless mode)
2. cgroups — how much a container can use
Control Groups enforce CPU shares, memory limits, block I/O bandwidth, and PIDs per cgroup. A runaway container hits the wall instead of starving the host.
3. Union filesystems (OverlayFS) — layered images
Images are stacks of read-only layers. Container runtime adds a thin writable layer on top. Same base layer? Stored once on disk, mounted into many containers. This is why pulling an image of "size 200MB" often only downloads 30MB — the rest you already have.