CoursesDocker in depthThe Docker engine

Configuring the daemon

daemon.json and engine defaults.

Intermediate12 min · lesson 6 of 30

The engine’s behaviour is configured in /etc/docker/daemon.json — the single source of truth for daemon-wide settings: where images and containers live (data-root), the default logging and storage drivers, registry mirrors and insecure registries, default resource ulimits, the default runtime, and more. It is the difference between per-container flags (this container) and engine policy (every container).

/etc/docker/daemon.json
{
"data-root": "/var/lib/docker",
"log-driver": "json-file",
"log-opts": { "max-size": "10m", "max-file": "3" },
"registry-mirrors": ["https://mirror.acme.internal"],
"default-ulimits": { "nofile": { "Name": "nofile", "Soft": 65536, "Hard": 65536 } },
"live-restore": true
}

Scenario: a node dies from its own logs

A host goes down not from load but from a full disk, and the culprit is a chatty container: the default json-file driver writes to disk and never rotates unless told to, so one verbose service fills /var/lib/docker over a weekend. Set max-size and max-file globally in daemon.json, or move to a driver that ships logs off-box (journald, or fluentd/syslog to a collector). Fix it before it bites, because the symptom looks like a mystery outage.

terminal
# per-container override to confirm behaviour before rolling out the daemon default
$ docker run -d --log-driver json-file --log-opt max-size=5m --log-opt max-file=2 nginx:1.27
$ docker inspect -f '{{.HostConfig.LogConfig}}' <id>
{json-file map[max-file:2 max-size:5m]}

Scenario: an internal registry over plain HTTP

A team runs an internal registry that (for now) serves plain HTTP, and pulls fail with an HTTPS error. registry-mirrors points Docker Hub pulls at a caching mirror so an upstream outage or rate limit does not stop builds; insecure-registries tells the daemon to allow a specific non-TLS registry. Use the mirror widely; use insecure-registries sparingly and only for hosts you control, since it disables transport security for them.

/etc/docker/daemon.json
{
"registry-mirrors": ["https://mirror.acme.internal"],
"insecure-registries": ["registry.dev.acme.internal:5000"]
}
# then: docker pull registry.dev.acme.internal:5000/app:1.0 (no TLS error)

Apply and validate safely

Changes take effect on daemon restart, and running containers survive it (with live-restore). The risk is a JSON typo: an invalid daemon.json stops dockerd from starting at all, and since dockerd serves the API, docker commands then fail with “cannot connect.” Validate before you restart, and keep a known-good copy.

terminal
$ sudo dockerd --validate --config-file /etc/docker/daemon.json
configuration OK
$ sudo systemctl restart docker
$ docker info -f '{{.LoggingDriver}} | data-root {{.DockerRootDir}}'
json-file | data-root /var/lib/docker
A bad daemon.json takes the engine down
A single misplaced comma stops dockerd from starting, and because the daemon is what answers the CLI, every docker command then errors out — alarming if you did not expect it. Always dockerd --validate the file first, keep a backup, and if you are locked out, read the failure with journalctl -u docker to find the offending line.