Docker Daemon
The background service (dockerd) that manages Docker objects — images, containers, networks, and volumes. The Docker CLI communicates with the daemon via a REST API over a Unix socket at /var/run/docker.sock.
What the Docker daemon does
The Docker daemon (dockerd) does the actual work behind every Docker command. When you run docker run nginx, the CLI sends a request to the daemon. The daemon pulls the image if needed, sets up networking and volumes, and asks lower-level components to start the container. The CLI is only a client.
sends the request"] --> D["dockerd
images, networks, volumes"] D --> C["containerd
container lifecycle"] C --> R["runc
namespaces and cgroups"] R --> P["Container process"] class CLI,C,R,P base class D key classDef base fill:#f8fafc,stroke:#94a3b8,stroke-width:1.5px,color:#0f172a classDef key fill:#dbeafe,stroke:#2563eb,stroke-width:2px,color:#0f172a
Kubernetes talks to containerd directly through the CRI, bypassing dockerd. This is why Kubernetes could drop Docker as a runtime and still run Docker-built images.
The Docker socket
The CLI reaches the daemon through the Unix socket /var/run/docker.sock. You can call the same REST API yourself:
ls -la /var/run/docker.sock# srw-rw---- 1 root docker ... /var/run/docker.sock curl --unix-socket /var/run/docker.sock http://localhost/containers/json# Same data as: docker psOnly root and members of the docker group can use the socket.
Configuration
The daemon reads /etc/docker/daemon.json. A typical production file:
{ "log-driver": "json-file", "log-opts": { "max-size": "100m", "max-file": "5" }, "storage-driver": "overlay2", "live-restore": true}log-driverandlog-optsset the default logging driver and rotate logs at 100MB, keeping 5 files.storage-driverselectsoverlay2, the recommended driver on modern Linux.live-restorekeeps containers running while the daemon restarts.
sudo systemctl status docker # Check the daemonsudo systemctl restart docker # Restart (stops containers unless live-restore is on)sudo journalctl -u docker.service -f # Follow daemon logsdocker info # Runtime, storage driver, containers, resourcesTroubleshooting
| Problem | Symptom | Fix |
|---|---|---|
| Daemon not running | Cannot connect to the Docker daemon |
sudo systemctl start docker |
| Permission denied | permission denied while trying to connect |
Add the user to the docker group, then log out and back in |
| Daemon fails after editing config | Start-up error | Check daemon.json for JSON syntax errors |
| Containers stop on daemon restart | live-restore not enabled |
Add "live-restore": true to daemon.json |
| Disk full | No space left on device |
docker system prune to remove unused objects |
TipEnable
live-restorebefore running production workloads. Without it, every daemon restart or upgrade stops all running containers.
SecurityAccess to the Docker socket is effectively root access on the host. Never mount it into containers you do not fully trust, never expose it over TCP without mutual TLS, and audit who belongs to the
dockergroup.
Frequently Asked Questions
What exactly happens when you run a docker command — where does the CLI end and the daemon begin?
The `docker` command you type is just a thin client; it serializes your request and sends it as a REST API call to `dockerd`, typically over the Unix socket at `/var/run/docker.sock` on Linux (or a named pipe on Windows). The daemon is the process that does the work: pulling image layers, creating namespaces and cgroups through containerd and runc, and managing the container lifecycle. That is why the CLI can be swapped out (Docker Desktop, remote Docker contexts) without touching daemon internals.
Why is exposing the Docker socket to a container considered a serious security risk?
Mounting `/var/run/docker.sock` into a container (a common pattern for CI runners or monitoring tools) effectively gives that container root access to the host, because the daemon runs as root and anyone who can talk to it can start a new privileged container with the host filesystem mounted in. If a container needs Docker API access, use a proxy such as `docker-socket-proxy` that restricts which API endpoints are reachable, rather than mounting the raw socket.