The Layered Runtime Architecture
In one sentence: "Docker" is not one program but a chain of four — CLI → daemon → container manager → OCI runtime — each layer knowing less about Docker and more about the kernel.
You already know
- From Lesson 1: the CLI is thin; the daemon owns images, containers, and registry traffic.
- From Lesson 2: "starting a container" means asking the kernel to create an isolated view and exec a process.
Why one brain became four programs
Early Docker was a monolith, and that caused two problems: restarting the daemon killed every container, and nobody else could reuse the container-running machinery. The fix was to split by lifespan and knowledge. The daemon keeps the high-level features (build, API, networks, volumes). A separate container manager (containerd in real Docker) owns container lifecycles. A tiny OCI runtime (runc) knows only how to talk the kernel into creating one container — then exits. And because someone must hold the container's stdio and exit code after runc leaves, a per-container shim process sticks around as the container's foster parent.
flowchart TB CLI["CLI
parses commands"] -- "REST API" --> D["Daemon
images · build · net · volumes"] D -- "gRPC" --> CD["Container manager
lifecycle · supervision"] CD -- "spawns per container" --> SHIM["Shim
holds stdio + exit code"] SHIM -- "invokes" --> RUNC["OCI runtime
creates container, then exits"] RUNC -- "namespaces, cgroups, exec" --> K["Kernel"] P["Container process"] --- SHIM K -. "gives birth to" .-> P
The disappearing runtime
The strangest part of the chain is that the component that actually creates containers is alive for under a second. The sequence makes the hand-offs visible — notice who remains standing at the end:
sequenceDiagram participant D as Daemon participant CD as Container manager participant S as Shim participant R as OCI runtime participant K as Kernel D->>CD: create container (bundle: rootfs + config) CD->>S: spawn shim for this container S->>R: run R->>K: create namespaces + cgroups R->>K: exec the app process R-->>S: done — runtime exits note over S: shim now parents the container,
holding stdio and waiting for exit S-->>CD: running (pid) CD-->>D: container started
This split buys real features: the daemon can be upgraded while containers keep running (the shims hold them), and any tool — not just Docker — can drive the same manager and runtime.
Anchor these
- Each layer down knows less about Docker, more about the kernel.
- The OCI runtime creates the container and exits; the shim stays as foster parent.
- The split means daemon restarts don't kill containers.
See what actually stuck.
Take the practice scenarios now.