01-foundations-containers

What a Container Actually Is: Processes, Namespaces and Layers

A container is not a small virtual machine — it's an ordinary Linux process wearing a blindfold. Understand the three kernel features behind it.

September 13, 2026
dockercontainersnamespacescgroupsoverlayfsocifundamentals

The Question Nobody Asks Out Loud

You can be productive with Docker for months on borrowed commands. docker run -p 8080:80 nginx works. docker build -t myapp . works. Then something breaks — a container that won't stop, a file that vanishes on restart, a 2GB image for a 40-line application — and the borrowed commands run out. Every one of those problems is easy once you know what a container is, and nearly impossible to reason about when you don't.

So here is the sentence the rest of this guide unpacks:

A container is a normal process running on the host's kernel, with a restricted view of the system.

That's it. No virtual machine, no guest operating system, no emulation layer. When you run a container on a Linux host, you can find its process in the host's own process list.

💡

This is the single biggest difference from a virtual machine. A VM ships an entire guest kernel and boots it on virtualised hardware. A container shares the host's kernel and just gets a restricted view of it — which is why a container starts in milliseconds while a VM takes tens of seconds.

Three Kernel Features Doing All the Work

"A restricted view" is the interesting part. The Linux kernel provides three separate mechanisms, and Docker combines them. They're worth learning as three distinct ideas, because they fail in three distinct ways.

Namespaces — what the process can see

A namespace wraps a global system resource so that the process inside believes it has its own private copy. Linux has several, and Docker uses them together:

  • PID namespace — your process sees itself as PID 1 and cannot see the host's other processes. This one has real consequences for how containers shut down, which the third guide in this phase covers.
  • Network namespace — its own network interfaces, IP address, routing table and ports. This is why two containers can both "listen on port 80" without colliding, and why localhost inside a container means the container, not your laptop.
  • Mount namespace — its own filesystem tree, so / inside the container is not the host's /.
  • UTS namespace — its own hostname.
  • IPC namespace — its own inter-process communication resources.
  • User namespace — its own user and group ID mapping, so UID 0 inside can map to an unprivileged UID outside.

cgroups — what the process can use

Namespaces limit visibility but not consumption. Without a second mechanism, one container could happily eat every byte of RAM on the host. Control groups (cgroups) meter and cap resource usage: CPU time, memory, block I/O, and the number of processes.

This is what's behind docker run --memory=512m. And when a container exceeds its memory cap, the kernel's OOM killer terminates it — the origin of the exit code 137 you'll meet in guide three.

Union filesystem — what the process can read

An image is built as a stack of read-only layers. A union filesystem (OverlayFS on modern Linux) presents that stack as a single merged directory tree, and adds one thin writable layer on top for the running container.

The rule that follows is the important one:

  • Reads fall through the stack until the file is found.
  • Writes go only to the writable top layer — the read-only layers underneath are never modified.
  • When the container is removed, that writable layer is deleted with it.

That last point is the entire reason volumes exist. It's also why a database container that was never given a volume loses everything the moment it's recreated.

Check yourself

Two containers are started from the same nginx image on one host. The first writes a 50MB log file to /var/log/nginx/ inside the container. What does the second container see at that path?

Image vs Container: The Distinction That Fixes Half Your Confusion

These two words get used interchangeably in conversation, and that habit causes real trouble. They are not the same kind of thing.

ImageContainer
What it isA stack of read-only layers plus a JSON configOne running (or stopped) instance of an image
Mutable?No — immutable once builtYes — has a writable layer
AnalogyA class, or an installerAn object, or an installed running program
Created bydocker builddocker run
Lives whereThe image store on disk, or a registryThe container list, until removed

One image can back a hundred containers, and the layers are stored once and shared. That's why the second container from an image starts almost instantly, and why pulling a new image that shares a base with one you already have downloads far less than its full size.

⚠️

A stopped container is still a container. It still holds its writable layer and still occupies disk. docker ps shows only running ones — docker ps -a shows the rest. A machine that's mysteriously out of disk very often has months of exited containers on it.

Why Images Are Portable: the OCI Standard

None of this would be much use if images only ran on Docker. They don't, and that's deliberate.

The Open Container Initiative (OCI) publishes two specifications that matter here:

  • The image specification — how a container image is structured: its layers, its manifest, its config.
  • The runtime specification — how a bundle on disk is turned into a running process.

Because these are open standards, an image built with docker build runs unchanged under containerd, Podman, CRI-O or Kubernetes. This is not a small detail. It's the reason Kubernetes could remove its Docker-specific runtime support in v1.24 without breaking anyone's images — those images were never Docker-specific in the first place. They were OCI artifacts all along.

Check yourself

A colleague says: 'Kubernetes dropped Docker support, so we need to rebuild all our images with a different tool.' What's wrong with that?

The Mental Model, Restated

When something behaves strangely later in this roadmap, come back to these four facts:

  1. The container is a process. If it exits, the container stops — there is nothing else keeping it alive.
  2. Namespaces decide what it can see. Network confusion, localhost surprises and PID 1 behaviour all trace back here.
  3. cgroups decide what it can use. Memory limits and OOM kills live here.
  4. The writable layer dies with the container. Anything you need to keep must live somewhere else.

Almost every Docker problem you'll hit is one of these four asserting itself.

What's Next

You now know what a container is. The next guide follows the chain of software that actually creates one — what happens between pressing Enter on docker run and a process existing — which explains why Docker needs a background daemon, why access to its socket is so dangerous, and where containerd fits into all of this.