Layer 2 — dockerd (Daemon / API Server)

Doosan published on
5 min, 837 words

Categories: post

Part 2 of the Docker layers series. From top to bottom, the stack is:

  1. docker CLI → 2. dockerd (daemon) → 3. containerd → 4. runc →
  2. Linux kernel. See the overview article.

Identity

dockerd is the Docker daemon: the long-running server process people usually imagine when they say "Docker." The docker CLI is only the client. dockerd is the server that does the actual management work. It listens on a socket, receives Docker API requests, and coordinates everything needed to handle them.

The familiar macOS error Cannot connect to the Docker daemon... Is the docker daemon running? points to this process. It means the CLI reached the socket path, but no dockerd was listening there, usually because the VM that runs it on a Mac is not up.

What it owns

dockerd owns every "Docker-level" concept except the raw act of running a container:

  • Images: pulling from registries, building with docker build, tagging, layer storage, and build cache management.
  • Networking: bridge network creation, port mapping (-p 8080:80), DNS between containers, and the default bridge/host/none networks.
  • Volumes and storage: named volumes, bind mounts, and storage drivers such as overlay2 that stack image layers.
  • API surface: the full Docker Engine API exposed to clients.
  • High-level objects: docker compose through the daemon, swarm mode, and plugins.

It does not directly perform the low-level container execution itself. It delegates that to containerd.

"Docker engine = server + api + client"

Docker Engine consists of three parts:

Docker Engine
├── client   →  docker (CLI)             [Layer 1]
├── api      →  Docker Engine REST API (contract between them)
└── server   →  dockerd (daemon)         [Layer 2]  ← this article

So on a Mac, "I installed Docker, but it does not run" usually means: the client is installed, but there is nowhere for the server (dockerd) to run. dockerd is a Linux process, and macOS is not Linux.

Why it cannot run natively on macOS

dockerd runs on Linux or Windows. On Linux it depends on kernel features such as namespaces, cgroups, and overlay filesystems. On Windows it depends on HCS, the Host Compute Service. It cannot run on top of the macOS Darwin kernel. This is the whole reason Docker Desktop, Colima, and Lima exist: they start a Linux VM and run dockerd inside it. Then the CLI on the Mac reaches into the VM through a forwarded socket.

# dockerd lives inside the Colima VM, not on the Mac:
$ colima ssh -- sh -c 'command -v dockerd; ps -e -o comm | grep dockerd'
/usr/bin/dockerd
dockerd

Breaking up the monolith: dockerd delegates downward

Docker was originally monolithic: one program served the API, managed images, and ran containers. Over time, it was split apart:

   Old (monolithic)                 Now
   ┌──────────────┐                  ┌──────────────┐  dockerd: API, images,
   │              │                  │   dockerd    │  networking, volumes
   │    docker    │                  └──────┬───────┘
   │  (all of it) │        →                │ gRPC
   │              │                  ┌──────▼───────┐  containerd: runtime,
   │              │                  │  containerd  │  lifecycle, image content
   └──────────────┘                  └──────┬───────┘

                                     ┌──────▼───────┐  runc: creates container
                                     │     runc     │  and exits immediately
                                     └──────────────┘

So when you run docker run, dockerd interprets the image and sets up networking and volumes. Then it calls containerd through a local gRPC API to actually start the container. dockerd stays alive to manage the whole system, while execution itself is delegated.

This separation is what allowed Kubernetes to drop dockerd ("dockershim removal"). Docker Engine did not implement the CRI natively, so Kubernetes had to maintain a bridge called dockershim. To remove that burden, Kubernetes talks directly to containerd, which implements CRI, and skips the entire dockerd layer.

Daemon configuration

dockerd behavior is controlled through daemon.json, which lives inside the VM when using Colima:

// /etc/docker/daemon.json
{
  "storage-driver": "overlay2",
  "registry-mirrors": ["https://..."],
  "log-driver": "json-file",
  "log-opts": { "max-size": "10m", "max-file": "3" }
}

On a normal Linux host, systemd starts dockerd (systemctl start docker), or you can run it in the foreground for debugging (sudo dockerd). In Colima, you normally do not start it yourself. colima start boots the VM, and the VM starts dockerd.

Alternatives that fill this slot

ToolDifference from dockerd
PodmanDaemonless: runs containers as child processes without an always-on server. Rootless by default.
CRI-OMinimal runtime dedicated to Kubernetes CRI. No Docker API and no build.
containerd aloneCan be used without dockerd, for example through nerdctl.

Summary

  • dockerd is the server. It owns images, networking, volumes, and the API.
  • "Docker daemon not running" means the server is not running. On a Mac, that usually means the VM is not running.
  • It is not the thing that runs containers at the lowest level. It delegates to containerd, the next layer.
  • Kubernetes skips this entire layer and talks directly to containerd.

References