The Daemon — Configuration and Storage Drivers
Everything in this book runs through one process: dockerd, the daemon that owns images, containers, networks, and volumes (Chapter 1, topic 05). Its behavior is configured in daemon.json — the default logging driver, the storage driver, registry mirrors, default network address pools — and its data lives under /var/lib/docker. The CLI is just a client talking to it; the daemon is where the state and the decisions are.
Knowing what daemon.json controls, which storage driver is in use, and what survives a daemon restart is the difference between operating a host and hoping it keeps running. The single fact that catches operators out is that the daemon reads its config at start time only — so a change to daemon.json is inert until a restart, and a bad change turns that restart into an outage.
daemon.json — The Host's Docker Config
daemon.json — at /etc/docker/daemon.json on Linux — is a single JSON file that sets daemon-wide defaults: log-driver and log-opts (so new containers inherit bounded logging from topic 66), storage-driver, registry-mirrors, default-address-pools, data-root, and more. A host config that bounds logging and pins the storage driver looks like this:
daemon.json controlsdaemon.jsonlog-driverstorage-driverdata-root/var/lib/docker by default{
"log-driver": "local",
"log-opts": { "max-size": "10m", "max-file": "3" },
"storage-driver": "overlay2",
"registry-mirrors": ["https://mirror.driftwood.example"]
}
The file is read once, at daemon start, so any change here needs a daemon restart to take effect. Editing it does nothing on its own — and the restart is where the risk lives.
Storage Drivers and Why overlay2
The storage driver implements the layered, copy-on-write image filesystem from Chapter 2 (topic 07). Among the classic storage drivers, overlay2 is the default on every current Linux kernel and the one to use — the older aufs, devicemapper, btrfs, and zfs exist for legacy kernels or specific filesystems, carry sharp edges and slower performance, and there is no reason to pick one on a current host. One shift to know: Docker Engine 29.0+ defaults fresh installs to the containerd image store, where containerd snapshotters (overlayfs under the hood) take the storage driver's place; upgraded hosts keep overlay2. docker info reports which backend is active:
docker info --format 'Storage Driver: {{.Driver}}'
If that prints something other than overlay2 on a modern kernel, you are either on a legacy classic driver someone configured deliberately, or on the containerd image store that fresh Docker Engine 29.0+ installs default to. Either way, switching the backend on a host that already holds images is not a casual edit, as the next mistake explains.
The Data Root — /var/lib/docker
All daemon state lives under /var/lib/docker: image layers, container writable layers, volumes, and networks. It grows with everything that is not pruned (topic 69), and when it fills, the daemon can no longer write and every container fails. Moving it to a larger disk means setting data-root in daemon.json and migrating the directory's contents — not symlinking it carelessly, which leaves the daemon and its tooling disagreeing about where state lives.
Registry Mirrors and Address Pools
registry-mirrors points the daemon at a pull-through cache to speed up and de-flake image pulls — every docker pull tries the mirror first. default-address-pools controls the subnets Docker hands to user-defined bridge networks, and it is the fix when Docker's default ranges collide with the corporate network the host sits on (ties to Chapter 7). On a routed network you decide those subnets deliberately rather than letting Docker pick ranges that overlap on-prem routes.
Restarting the Daemon — What Survives
Restarting dockerd re-reads daemon.json. Stopped containers, images, and volumes all persist across the restart because they live in /var/lib/docker, not in the daemon's memory. Running containers can keep running across a daemon restart with --live-restore enabled; what is lost is anything that existed only in the daemon's runtime state. The thing to remember is that a config change to an existing container — a new log driver, a different limit — still requires recreating that container; the daemon restart applies the new defaults only to containers created afterward.
Validating Config Before Restart
A malformed daemon.json makes dockerd refuse to start, taking every container on the host offline at the worst possible time. The defense is to validate before you restart:
dockerd --validate
That checks the file for the JSON error or unknown key that would otherwise leave the host with a dead daemon and no containers. A trailing comma you would never notice in an editor is exactly the kind of thing it catches before it becomes an outage.
- Editing
daemon.jsonwith a trailing comma or other JSON error and restarting —dockerdrefuses to start, and every container on the host goes down until the file is fixed; validate before restarting. - Switching the storage driver on a host with existing images and containers — changing
storage-drivermakes the daemon unable to see the data stored under the previous driver, effectively orphaning every image and container. - Filling
/var/lib/dockerbecause it sits on a small root partition that was never moved or pruned — the daemon can no longer write and all containers fail; either set a largerdata-rootor schedule pruning (topic 69). - Setting a default
log-driverorlog-optsindaemon.jsonand expecting running containers to adopt it — only containers created after the restart inherit daemon defaults; existing ones keep their old config (the same trap as topic 66). - Leaving Docker's default
default-address-poolswhen the host lives on a corporate network using the same RFC 1918 ranges — new bridge networks collide with on-prem routes and traffic silently goes to the wrong place (ties to Chapter 7).
- Set host-wide defaults in
daemon.json— boundedlog-driverandlog-opts, theoverlay2storage driver, anyregistry-mirrors— so every new container inherits safe behavior without per-container flags. - Run
dockerd --validate(or otherwise lint the JSON) before restarting the daemon, since a baddaemon.jsonkeeps the daemon from starting at all. - Keep
/var/lib/dockeron a disk sized for image and volume growth, or relocate it withdata-root, and pair it with the pruning schedule from topic 69. - Set
default-address-poolsto ranges that do not collide with the network the host sits on, deciding the subnets deliberately rather than accepting Docker's defaults on a routed corporate network.
config.toml and the overlayfs snapshotter as the storage-driver analog
Podman daemonless — settings live in containers.conf/storage.conf per user
nerdctl info reports the active driver and data root the way docker info does
Knowledge Check
You edit daemon.json to set a new default log driver. Why does the change not take effect immediately?
- The daemon reads
daemon.jsononly at start, so the change is inert untildockerdis restarted - The daemon polls the file on a fixed interval every few minutes and will quietly pick it up on the next cycle
- It needs a separate
docker config applycommand to be run before it loads the new file - The CLI caches a copy of the old config and must be fully reinstalled to clear it
What happens if you change storage-driver on a host that already has images and containers under the old driver?
- The daemon can no longer see the data stored under the old driver, orphaning every existing image and container
- Docker transparently migrates all of the existing layers into the new storage driver's on-disk format
- Only the containers created after the switch use the new driver, while all the existing ones remain unaffected and stay fully visible as before
- The daemon flatly refuses to start until you delete the old driver's data directory manually first
After restarting dockerd, why do your stopped containers, images, and volumes still exist?
- They live on disk under
/var/lib/docker, not in the daemon's memory, so a restart re-reads them - The
--live-restoreflag keeps stopped containers and volumes from being deleted on restart - The daemon snapshots all of its state to a backup file just before it shuts down and restores it on start
- The daemon re-pulls every image, container, and volume from the registry as it starts back up
Why run dockerd --validate before restarting the daemon after editing daemon.json?
- A malformed
daemon.jsonmakes the daemon refuse to start, taking every container offline;--validatecatches the error first - It runs each individual container's configured healthcheck ahead of time to first confirm that they will all come back up cleanly
- It applies the new config live to the running daemon so that no restart is needed at all
- It prunes the
/var/lib/dockerdirectory so the daemon has free room to restart
You got correct