Docker from First PrinciplesPost 4 of 18 · 18 of 18 written

4. Docker's architecture

Docker · 4 of 183 min readOct 2026

The docker command is a thin client. The real work happens in a chain: the CLI calls the Docker Engine API, dockerd asks containerd to run a container, containerd starts a small shim, the shim calls runc, and runc sets up namespaces and cgroups, then replaces itself with your process. The diagram below follows that chain.

[embedded content: Docker’s component chain · CLI to your process]

Read it top to bottom: each component hands the job one level down. Once your process runs, runc has already exited and the shim stays as its parent; on a Linux server there is no VM, and the outer box is simply the host.

The components, one by one

  • Docker CLI. Turns docker run … into REST calls to the Engine API. By default it talks over the Unix socket /var/run/docker.sock; DOCKER_HOST or docker context can point it at a remote engine over SSH.
  • dockerd (Docker Engine). Serves the API and owns the Docker-level concepts: networks, volumes, port publishing, logging drivers, and builds. It delegates containers and images to containerd.
  • BuildKit. The build engine behind docker build, the default since Docker Engine 23. It runs independent build stages in parallel and provides cache mounts, secret mounts and multi-platform builds. docker buildx is its full-featured command-line front end.
  • containerd. A general-purpose container daemon: pulls and stores images, creates and supervises containers. Kubernetes nodes usually run containerd directly, with no Docker involved.
  • containerd-shim. One small process per container. It holds the container’s input and output, reports its exit status, and keeps it running if dockerd or containerd restarts, so you can upgrade Docker without killing workloads.
  • runc. The low-level OCI runtime. It reads a runtime spec, creates the namespaces and cgroups, mounts the root filesystem, drops privileges, and then executes your process. Once your process is running, runc exits.
  • Runtime hooks. The NVIDIA Container Toolkit plugs into this chain to inject GPU device files and driver libraries as the container is created (Part 10). Alternative runtimes such as gVisor’s runsc or Kata Containers can replace runc for stronger isolation.

Why the layering matters

Kubernetes removed its built-in Docker support in version 1.24 and talks to containerd directly. Images built with docker build still run there unchanged, because the hand-off format between all these tools is the OCI image. Knowing the chain also tells you where to look: a build problem is BuildKit, a pull problem is containerd and the registry, a “permission denied” at start is often runc applying security settings.

The socket is root

Anyone who can send requests to docker.sock can start a container that mounts the host’s / and runs as root, which is full control of the machine. On Linux, being in the docker group is therefore equivalent to having root. Remember this whenever a tool asks you to mount the socket into a container (Part 13).

Docker Desktop on your Mac

Docker Desktop runs dockerd, containerd and runc inside a lightweight Linux VM, using Apple’s virtualization framework. The docker CLI on macOS talks to the engine through a forwarded socket, and published ports are forwarded from the VM to your Mac’s localhost, which hides the VM most of the time.

Three consequences are worth knowing on an M1 Pro:

  1. Architecture. The VM is arm64. arm64 images run natively; amd64 images run under emulation (Rosetta or QEMU), which is slower and occasionally breaks native code.
  2. File sharing. Bind mounts from macOS cross the VM boundary (via VirtioFS). Workloads touching many small files, such as a Python environment on a bind mount or a dataset of small images, run noticeably slower than on native Linux.
  3. Resources. Containers share the VM’s CPU, memory and disk allocation, set in Docker Desktop’s settings. A container that hits the VM’s memory ceiling dies even when macOS has RAM free.

OrbStack, Colima and Podman Desktop are alternatives that work the same way: a Linux VM with a container engine inside.