Engine architecture
dockerd, containerd, shim, and runc.
“Docker” is not one program but a small stack of daemons, and knowing the split explains a surprising amount of behaviour. The Docker daemon (dockerd) serves the API and manages images, networks, and volumes. It delegates container lifecycle to containerd. containerd starts a lightweight shim process per container, and the shim invokes runc — the low-level OCI runtime that makes the actual Linux calls (clone, namespaces, cgroups, pivot_root) to become the container. runc then exits; the shim stays as the container’s parent.
$ ps -ef | grep -E "dockerd|containerd|shim" | grep -v greproot dockerdroot containerdroot containerd-shim-runc-v2 -namespace moby -id 7f8e9d0a... -address /run/containerd/...# └ one shim per running container; note there is no runc — it already exited
Scenario: restart the daemon without an outage
You need to change daemon.json, which requires restarting dockerd — but you cannot drop the running containers. Because the shim (not dockerd) is each container’s parent, containers survive a daemon restart; with live-restore enabled they keep running even while dockerd is down, and reconnect when it returns. Turn it on so daemon maintenance is not a workload outage.
# /etc/docker/daemon.json -> { "live-restore": true }$ sudo systemctl restart docker$ docker ps # the containers are still Up — the shims held themCONTAINER ID IMAGE STATUS7f8e9d0a1b2c nginx:1.27 Up 40 minutes
Scenario: no dockerd at all (why Kubernetes dropped it)
On a Kubernetes node there is often no Docker daemon — the kubelet talks to containerd directly through the CRI, because dockerd was just an extra hop. You can inspect that lower layer with containerd’s own client, ctr, or the friendlier nerdctl. Seeing the same containers through ctr that you started through docker makes the layering concrete: docker is a convenience on top of containerd, not the thing running your containers.
$ sudo ctr -n moby containers ls # containerd’s own view (moby = docker’s namespace)CONTAINER IMAGE RUNTIME7f8e9d0a... docker.io/nginx:1.27 io.containerd.runc.v2# on a k8s node the namespace is k8s.io, and there is no dockerd in ps at all