Before Docker

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.

Bash
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:

Bash
# 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.

Bash
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:

Bash
docker run -it ubuntu bash