THIS EXPLANATION
THE ROOM
CDA·120 Computing, Data & AI 7 MIN · 8 STATIONS

Isolation without a machine

A Socratic walk-through of isolation without a machine — reasoned out one step at a time, not lectured.

abcdefgh
a

The question we started with

THE QUESTION #

How can a program be walled off from everything else on a computer without a computer of its own?

A container feels like a small computer. It has its own hostname, its own filesystem, its own process list where your application is process number one, its own network address. Log into one and it is hard to tell you are not on a machine.

But no machine was created. There is one kernel, one set of physical CPUs, one real filesystem. So the question is what exactly was built — and the more useful version of it: if the container is not a computer, what is the boundary made of, and where does it stop?

b

Reasoning it through

REASONING #

Start from the opposite end. Instead of asking how to build a small computer, ask what a process would have to be unable to see for it to believe it was alone. It would have to not see other processes. It would have to see a filesystem containing only its own files, its own hostname, its own network interfaces and ports, user IDs that mean something local.

Now notice something about that list. Every item is a view. None of them is a physical thing. The process is not asking for its own CPU; it is asking for a consistent story about its surroundings. And a story is much cheaper to produce than a machine.

Follow that. Where do those views come from? All of them come from the kernel. When a process asks what processes exist, the kernel answers. When it opens a path, the kernel resolves it. When it binds a port, the kernel assigns it. The kernel is the sole narrator of the environment — so to give a process a different environment you do not need different hardware, only a narrator telling it a different story.

That is precisely what a Linux namespace is. Each kind covers one category of global resource and gives a group of processes their own instance of it: mount points, the process ID table, network stacks, hostname, inter-process communication objects, user and group ID mappings, control-group membership, and the system clock offset. A process placed in a fresh set of these sees a self-consistent world, because every question it can ask is answered from within its own instances.

Now a second question. Does that stop the process consuming the whole machine? It does not — namespaces are about visibility, not quantity. A process that cannot see its neighbours can still exhaust the memory they need. So a separate mechanism is required: control groups, which meter and cap CPU time, memory, block I/O and process counts. Two mechanisms, two jobs — and conflating them causes a lot of confusion, because "isolation" is used loosely to mean both.

A third question: does the process still have the full power of the kernel available? By default, yes — every system call is reachable. That is a very wide surface, so runtimes narrow it deliberately: dropping Linux capabilities so the process cannot load kernel modules or change system time; applying a seccomp filter that blocks calls the workload never needs; often adding a policy such as SELinux or AppArmor.

Put those three together and the picture is clear. A container is not an object at all. It is an ordinary process that the kernel has been asked to lie to about its surroundings, meter, and restrain. There is no container object anywhere in the kernel — which is why ps on the host shows container processes as plain processes with ordinary PIDs, because from the host's namespace that is exactly what they are.

That also tells you where the boundary ends. All of this is enforced by one kernel, shared by every container and by the host, so a flaw in that kernel is a flaw in every wall at once. A virtual machine differs in kind: it runs a separate guest kernel on virtualised hardware, so an escape must get through the guest kernel and the hypervisor. That is the honest reason containers are called weaker isolation than VMs — not worse performance, but fewer independent layers in the trust boundary. It is also why Firecracker and gVisor exist, putting a thin extra boundary under a container-shaped interface.

c

The analogy

THE ANALOGY #
THE FIGURE

Think of a hotel that gives a long-stay guest a room with a nameplate reading "Flat 1", a private letterbox, and a curated directory listing only that room, so that as far as the guest can tell they live in a one-flat building. The illusion is maintained entirely by the front desk, which answers every question the guest can ask. Meanwhile the hotel manager separately meters how much hot water and electricity each room may draw.

Nothing was built. The rooms already existed; the front desk simply answers selectively, and the meters cap consumption.

WHERE IT BREAKS DOWN

a guest could walk down the corridor and see the truth for themselves, whereas a contained process has no corridor at all — every observation it can make is mediated by the kernel, which is why the illusion is total in a way a hotel's never could be, and why a fault in the front desk is the only way through.

d

Clarifying the model

THE MODEL #

Three refinements.

First, the misconception this most often corrects: containers do not virtualise anything. There is no emulated hardware and no guest operating system, so a container image contains no kernel — only userspace files. This is why a Linux container needs a Linux kernel underneath, and why running one on another operating system quietly starts a real virtual machine to supply that kernel.

Second, the pieces were built separately. Namespaces landed across many years — the mount namespace as early as 2002, the user namespace not until 2013 — and control groups arrived independently. Docker invented none of them; it packaged them with an image format and made the combination easy to use, which is a real contribution but a different one.

Third, isolation is a spectrum you configure, not a state you occupy. A container running as root with the host's process namespace shared in and no seccomp profile has almost none of the boundary described here, and is still correctly called a container. The word names the packaging, not a guaranteed level of separation.

e

A picture of it

THE PICTURE #
Isolation without a machine
Isolation without a machine Read the four branches as four independent mechanisms, not as stages of a pipeline. The first is what makes the container look like a machine, and it is pure visibility. The second is what stops it eating the machine, and it is pure accounting -- nothing in it hides anything. The third is what stops it doing dangerous things. The fourth matters most for security reasoning: everything absent from the first three is shared, and the single kernel heading it is the boundary a container cannot double up. {"generator":"[email protected]","source":"../Socrates/.diagram-cache/_src/isolation-without-a-machine.md","sourceIndex":1,"sourceLine":4,"sourceHash":"803ade8efd444b8f14719555286fced8d98ac09cfe47b268d00ce23cd6336646","diagramType":"mindmap","layoutVariant":"source","repairedDuplicateIds":[{"original":"mermaid-803ade8efd444b8f-0-node_1","replacement":"mermaid-803ade8efd444b8f-0-node_1--duplicate-2"},{"original":"mermaid-803ade8efd444b8f-0-node_2","replacement":"mermaid-803ade8efd444b8f-0-node_2--duplicate-2"},{"original":"mermaid-803ade8efd444b8f-0-node_3","replacement":"mermaid-803ade8efd444b8f-0-node_3--duplicate-2"},{"original":"mermaid-803ade8efd444b8f-0-node_4","replacement":"mermaid-803ade8efd444b8f-0-node_4--duplicate-2"},{"original":"mermaid-803ade8efd444b8f-0-node_5","replacement":"mermaid-803ade8efd444b8f-0-node_5--duplicate-2"},{"original":"mermaid-803ade8efd444b8f-0-node_6","replacement":"mermaid-803ade8efd444b8f-0-node_6--duplicate-2"},{"original":"mermaid-803ade8efd444b8f-0-node_7","replacement":"mermaid-803ade8efd444b8f-0-node_7--duplicate-2"},{"original":"mermaid-803ade8efd444b8f-0-node_8","replacement":"mermaid-803ade8efd444b8f-0-node_8--duplicate-2"},{"original":"mermaid-803ade8efd444b8f-0-node_9","replacement":"mermaid-803ade8efd444b8f-0-node_9--duplicate-2"},{"original":"mermaid-803ade8efd444b8f-0-node_10","replacement":"mermaid-803ade8efd444b8f-0-node_10--duplicate-2"},{"original":"mermaid-803ade8efd444b8f-0-node_11","replacement":"mermaid-803ade8efd444b8f-0-node_11--duplicate-2"},{"original":"mermaid-803ade8efd444b8f-0-node_12","replacement":"mermaid-803ade8efd444b8f-0-node_12--duplicate-2"},{"original":"mermaid-803ade8efd444b8f-0-node_13","replacement":"mermaid-803ade8efd444b8f-0-node_13--duplicate-2"},{"original":"mermaid-803ade8efd444b8f-0-node_14","replacement":"mermaid-803ade8efd444b8f-0-node_14--duplicate-2"},{"original":"mermaid-803ade8efd444b8f-0-node_15","replacement":"mermaid-803ade8efd444b8f-0-node_15--duplicate-2"},{"original":"mermaid-803ade8efd444b8f-0-node_16","replacement":"mermaid-803ade8efd444b8f-0-node_16--duplicate-2"},{"original":"mermaid-803ade8efd444b8f-0-node_17","replacement":"mermaid-803ade8efd444b8f-0-node_17--duplicate-2"},{"original":"mermaid-803ade8efd444b8f-0-node_18","replacement":"mermaid-803ade8efd444b8f-0-node_18--duplicate-2"},{"original":"mermaid-803ade8efd444b8f-0-node_19","replacement":"mermaid-803ade8efd444b8f-0-node_19--duplicate-2"},{"original":"mermaid-803ade8efd444b8f-0-gradient","replacement":"mermaid-803ade8efd444b8f-0-gradient--duplicate-2"}],"motion":"entrance-with-reduced-motion-fallback","presentation":"editorial","attempt":1,"viewBox":{"x":0,"y":0,"width":1428,"height":621},"qa":{"passed":true,"findings":[]}} A contained process What the kernel hides Mount namespace givesits own filesystem view PID namespace makes itprocess one Network namespacegives it its own ports UTS namespace gives itits own hostname User namespace remapsits user IDs What limits how much ittakes CPU shares and quotas Memory ceiling Block IO weight Process count cap What narrows what it maydo Dropped Linuxcapabilities Seccomp system call filter SELinux or AppArmorpolicy What is still shared One kernel for host andcontainers The physical CPUs andmemory The system call interfaceitself

How to readRead the four branches as four independent mechanisms, not as stages of a pipeline. The first is what makes the container look like a machine, and it is pure visibility. The second is what stops it eating the machine, and it is pure accounting — nothing in it hides anything. The third is what stops it doing dangerous things. The fourth matters most for security reasoning: everything absent from the first three is shared, and the single kernel heading it is the boundary a container cannot double up.

f

What became clearer

WHAT CLEARED #
WHAT CLEARED

A container is not a small machine but an ordinary process given a private set of kernel-maintained views, a resource budget, and a narrowed set of permitted operations. Because every one of those walls is enforced by the same kernel the host runs, the isolation is real, cheap, and single-layered — which is exactly the trade being made against a virtual machine.

g

Where to go next

ONWARD #
  • User namespaces and rootless containers: mapping a container's root to an unprivileged host user.
  • What a seccomp profile actually blocks, and how much of a default profile a typical workload needs.
  • Lightweight virtual machines such as Firecracker, and where they sit between the two models.
h

Key terms

TERMS #
TermWhat it means
Namespacea kernel facility giving a group of processes their own instance of a global resource, such as the process table or the network stack.
Control group (cgroup)a kernel facility that meters and limits the CPU, memory, and I/O a group of processes may consume.
Capabilityone of the divisible privileges making up traditional root power, each droppable independently.
Seccompa filter restricting which system calls a process may make.
Hypervisorthe layer running guest operating systems on virtualised hardware, supplying the extra kernel boundary containers lack.

Every term the collection defines is gathered in the glossary.

Nearby on the shelf

4