C.W.K.
Stream
Lesson 05 of 07 · published

Engine Architecture — CLI, dockerd, containerd, runc

~14 min · foundations, architecture

Level 0Container Curious
0 XP0/36 lessons0/10 achievements
0/120 XP to next level120 XP to go0% complete

What happens when you type docker run nginx

It looks like one command. It is actually four programs cooperating.

┌─────────────┐    ┌──────────────┐    ┌────────────┐    ┌────────┐
│ Docker CLI  │───▶│ dockerd      │───▶│ containerd │───▶│  runc  │
│  (docker)   │    │ (REST daemon)│    │ (lifecycle)│    │ (OCI)  │
└─────────────┘    └──────────────┘    └────────────┘    └────────┘

Each layer's job

  • Docker CLI (docker) — the command-line client you actually type. Talks to dockerd over a Unix socket (/var/run/docker.sock) or TCP.
  • dockerd — the background daemon. Manages images, networks, volumes, and the public Docker REST API. This is what restarts when you "restart Docker."
  • containerd — the runtime that actually manages container lifecycle: pulls images, starts processes, attaches to namespaces. CNCF graduate. Runs containers for both Docker AND Kubernetes.
  • runc — the low-level OCI-compliant runtime. Spawns the actual Linux process inside namespaces and cgroups. Tiny. Boring. Critical.

Why the layers matter

You can swap pieces. Kubernetes' kubelet talks to containerd directly, skipping dockerd entirely. Podman skips dockerd too — it's a CLI that drives runc directly, daemonless. The OCI standard is what makes this swappability possible.

Code

See the layers on a running host·bash
# The processes
ps -ef | grep -E 'dockerd|containerd|runc' | grep -v grep

# A typical Linux host:
# root   1234  ... /usr/bin/dockerd
# root   1245  ... /usr/bin/containerd
# (runc is short-lived — it forks the container and exits)

# CLI talks to daemon via unix socket
ls -l /var/run/docker.sock
# srw-rw---- 1 root docker 0 ... /var/run/docker.sock
Talk to dockerd directly without the CLI·bash
# The Docker CLI is just a REST client. You can call the API yourself.
curl --unix-socket /var/run/docker.sock http://localhost/v1.43/containers/json

# Returns JSON for every running container —
# the same data 'docker ps' shows.

External links

Exercise

On a Linux host (or in a Linux VM), run pstree while a container is running. Identify the dockerd → containerd → containerd-shim → your-app chain. Write down the PIDs. Then docker stop the container and run pstree again — which processes disappeared, which stayed?

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.