Containers·7 min read·

Docker Log Drivers, Rotation, and Management

Configure Docker log drivers and rotation so containers never fill your disk, and learn which driver keeps docker logs working and which takes them away.

NB

Netbay Cloud Team

Netbay Engineering

On this page

Container logs are a disk time bomb. Docker captures everything the process writes to stdout and stderr, and by default it writes that stream, unbounded, to a JSON file on the host. A verbose application that logs a few hundred MB per day — read that again, per day — turns the free space on a VPS into a countdown unless the daemon is configured to rotate. Logging is also where the driver decision lives: the common json-file driver is what makes docker logs work, and switching drivers can silently disconnect you from the one logging tool you already know. This guide covers the defaults, the rotation settings that prevent the disk-full outage, and how to pick a driver without losing observability.

From container output to log management container stdout/stderr driver json-file local / syslog rotation max-size max-file consume docker logs or central store Bound it locally, then decide where it goes long-term

Where Container Logs Actually Land

By default the docker daemon reads the container's stdout and stderr and appends every line as JSON to a file under the daemon's data directory — one file per container, named after the container ID. The file grows without a built-in ceiling until you configure one. Belt and suspenders: the application should log to stdout, the driver should rotate by size, and whoever operates the host should know where the files live before disk pressure makes the knowledge mandatory.

Rotation: The Configuration That Prevents the Outage

Rotation lives in the daemon settings, in /etc/docker/daemon.json, and applies to any new containers the daemon starts (existing containers keep their old settings until recreated).

json
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "20m",
    "max-file": "5"
  }
}

With that, each container's log is capped at five 20 MB files — 100 MB worst case per container — instead of an unbounded file that quietly fills the disk. After editing daemon.json, restart the daemon and recreate the containers that should pick up the new cap. The daemon-level default is the important part: setting rotation per container works, but a new container started by someone who forgot is unprotected again.

Picking a Log Driver Without Losing docker logs

The json-file driver (optionally with rotation, above) is where docker logs works out of the box. The local driver is a lighter, faster alternative that also stores in the daemon and also supports docker logs, but uses a binary format the host tools cannot read directly. The journald driver routes lines into the host's systemd journal — unified with system services, but docker logs goes quiet because the daemon is no longer the store. syslog, fluentd, and gelf forward to external aggregators, and with them the docker logs command prints nothing; your log viewer is the aggregator. The rule: if you rely on docker logs, stay on json-file or local; if you forward, choose the forward target deliberately and lose the local command on purpose.

bash
# Per-container override stays on top of the daemon default
docker run -d --name web --log-driver json-file   --log-opt max-size=10m --log-opt max-file=3   -p 8080:80 nginx:alpine

# Confirm what a running container actually uses
docker inspect web --format 'driver={{ .HostConfig.LogConfig.Type }} opts={{ .HostConfig.LogConfig.Config }}'

The inspect line is the habit that prevents surprises: it reports in seconds whether a container is on the rotated local driver or the un-capped default, which is exactly the difference between a disk scare and a clean weekend.

Compose-Level Logging Configuration

Compose exposes the same options so rotation stays in version control with the rest of the stack.

yaml
name: shop
services:
  web:
    image: nginx:alpine
    ports:
      - "8080:80"
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"
    restart: unless-stopped

Keeping logging policy in the compose file means a new environment inherits the cap instead of re-discovering it after the first disk-full alert. When the stack outgrows one host, replace the driver block with a forwarding driver and send the same lines to a central aggregator — the compose shape does not change.

Managing What You Already Have

Rotation caps future growth but does not shrink already-large logs. For existing containers, rotate by hand: stop the container, remove the oversized files under the per-container log directory, and recreate it. A cron check on disk usage is the pragmatic sentinel that catches the app that stops responding to drivers entirely:

bash
du -sh /var/lib/docker/containers/*/*-json.log | sort -rh | head
find /var/lib/docker -name '*-json.log' -size +100M -exec ls -lh {} ;
docker ps -s

The second find lists only logs above 100 MB — likely candidates for a hand rotate or a driver re-check. A container whose json log is one of the top consumers of host disk is a container whose rotation configuration is missing, and the file path tells you the container ID to inspect.

Takeaway

Bounded local logs prevent the disk-full outage, and the driver decision is really a decision about where docker logs keeps working. Set max-size and max-file in the daemon defaults, keep the compose file explicit, and inspect the driver when something behaves unexpectedly. On a Netbay VPS, where you own the whole disk and the dashboard, capping container logs from day one is the difference between a quiet week and a disk-full emergency at 3 AM — configure it at netbayhosts.in.

Keep reading

Follow along on a real VPS

Deploy Linux in under 60 seconds

These guides are written against Ubuntu, Debian, and RHEL-family images — the same ones on NetBay.

Deploy an instance