Imagine a fresh linux installation.
You may want to run a program.
A program is a file on a disk.
A process is a running instance of that program.
Why do we want isolation?
Security, Fault containment, Multi-tenancy
Step 0: chroot: first steps towards Isolation
One of the oldest isolation tools in Linux is chroot, which changes the root directory (/) for a process and its children. This creates the illusion of a different filesystem – a restricted view of the world.
Step 1: Namespaces: Isolation done for real
Linux introduced namespaces to isolate different aspects of a process’s environment:
PID namespace: isolate process IDs.
NET namespace: give each container its own network stack.
MNT namespace: isolate mount points (different filesystems).
UTS namespace: different hostnames and domains.
IPC namespace: isolate shared memory, message queues, etc.
USER namespace: map user IDs inside to different IDs outside.
unshare --pid --fork --mount-proc bash
Why? It’s late 1990’s – you are on a shared VPC and a “ps” lets you see every other process on the machine.
Step 2: cgroups: Resource Control
Cgroups let you allocate and restrict resources:
# Create a cgroup
$ mkdir /sys/fs/cgroup/mygroup
$ echo $$ > /sys/fs/cgroup/mygroup/cgroup.procs
$ echo 50000 > /sys/fs/cgroup/mygroup/memory.max
# Now the current process (and children) are limited to ~50 MB RAM.
Why? Its mid 2000’s – one team deploys a binary and your machines crawl to a stop. How do you contain the blast radius?
Step 3: Union Filesystems and Layers
A union filesystem lets you mount multiple directories (layers) on top of each other, so they appear as one unified filesystem – this saves space!
UnionFS (1990s), later AUFS, and eventually OverlayFS in the Linux kernel allowed you to mount multiple directories “on top” of each other.
mount -t overlay overlay \
-o lowerdir=/base,upperdir=/changes,workdir=/work \
/merged
By now, we’ve seen that Linux already had all the building blocks for isolation and lightweight environments:
- chroot → filesystem view isolation
- Namespaces → process, network, IPC, and identity isolation
- cgroups → resource control
- Union filesystems → efficient image layering
Why? Every VM has its own full copy of Linux on the same machine.
Then Docker (2013)
Before Docker, you could combine these pieces manually — but it was complex, error-prone, and not portable. Docker’s contribution was to compose these primitives into one coherent tool:
docker run -it ubuntu bash