DevOps• 5 MIN READ
Kirito

Kirito

6/10/20265 min read

The Docker Volume That Accumulated 200GB of Logs (And Killed the Server)

A Docker container wrote logs to an anonymous volume. 6 months later, that volume had 200GB of log files and brought the entire server down.

The Docker Volume That Accumulated 200GB of Logs (And Killed the Server)

"No disk space left."

I SSH'd into our production server. df -h showed 0% available.

The server had been running for 6 months without issues. What changed?

Nothing. That was the problem.

The Setup

We ran a Node.js app inside a Docker container:

FROM node:18 WORKDIR /app COPY . . RUN npm ci CMD ["node", "app.js"]

The app wrote logs to /app/logs/app.log.

We started the container with:

docker run -d --name myapp myapp:latest

No volume mount. No log rotation. No size limits.

The Hidden Accumulation

Docker creates anonymous volumes for any directory that writes data inside the container, unless you explicitly mount something there.

/app/logs became an anonymous volume.

Every day, the app wrote ~1GB of logs.

After 6 months: ~180GB.

But Docker doesn't clean up anonymous volumes automatically. They persist even after the container stops.

Our server had a 250GB disk. The logs took 180GB. The rest was the OS, Docker images, and other containers.

When the disk filled up:

  • The app couldn't write logs (but kept retrying, consuming CPU)
  • The database container couldn't write WAL files
  • SSH became sluggish
  • The entire server became unusable

The Investigation

# Check disk usage df -h Filesystem Size Used Avail Use% Mounted on /dev/xvda1 250G 250G 0G 100% / # Find large files du -sh /var/lib/docker/volumes/* | sort -h 180G /var/lib/docker/volumes/3f8a9b2c.../_data # Look inside sudo ls -la /var/lib/docker/volumes/3f8a9b2c.../_data -rw-r--r-- 1 root root 180G app.log

That anonymous volume had 180GB of logs.

The Emergency Fix

1. Stop the container

docker stop myapp

2. Remove the anonymous volume (DANGER: data loss)

# List volumes docker volume ls # Remove the specific volume docker volume rm 3f8a9b2c...

3. Free up space

# Prune everything docker system prune -a --volumes

4. Restart with proper logging

docker run -d --name myapp --log-opt max-size=10m --log-opt max-file=3 --mount type=bind,source=/var/log/myapp,target=/app/logs myapp:latest

The Proper Fix

1. Use Docker logging driver with limits

# daemon.json (global) { "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3", "compress": "true" } }

2. Never write logs to a file inside container – write to stdout

// app.js - use console.log instead of file transport const logger = winston.createLogger({ transports: [ new winston.transports.Console({ format: winston.format.json() }) ] });

Then Docker captures stdout and applies log rotation.

3. Use a dedicated log volume with rotation

# Create a volume with log rotation using a sidecar container docker run -d --name log-rotator -v myapp-logs:/logs docker.io/ubuntu:latest sh -c "while true; do logrotate /etc/logrotate.conf; sleep 3600; done"

4. Set up log shipping to external system

# Use fluentd or vector to ship logs to S3/ELK docker run -d --log-driver=fluentd --log-opt fluentd-address=localhost:24224 myapp:latest

The Monitoring

We added disk usage alerts:

#!/bin/bash # check-disk.sh USAGE=$(df / | tail -1 | awk '{print $5}' | sed 's/%//') if [ $USAGE -gt 85 ]; then curl -X POST -H 'Content-type: application/json' --data "{"text":"Disk usage at $ {USAGE}% on $(hostname)"}" $SLACK_WEBHOOK fi

The Prevention Checklist

  • [ ] Containers write logs to stdout, not files.
  • [ ] Docker daemon has log rotation configured.
  • [ ] Anonymous volumes are avoided (always name volumes).
  • [ ] Disk usage monitoring is in place.
  • [ ] 'docker system prune' runs weekly in cron.

Commands to Audit Volumes

List all volumes with size

docker run --rm -v /var/run/docker.sock:/var/run/docker.sock alpine/du:latest /var/lib/docker/volumes

Find unused volumes

docker volume ls -qf dangling=true

Inspect volume contents

docker run --rm -v my_volume:/data alpine ls -la /data

What I Learned

  • Anonymous volumes are persistent and grow forever.
  • Docker's default logging has no limits unless configured.
  • Writing logs to files inside containers is an anti-pattern.
  • 'docker system prune -a --volumes' is your friend in emergencies.

That 200GB of logs cost us 2 hours of downtime and a very angry customer. Now every container writes to stdout and we ship logs to Datadog. Disk alerts saved us twice since then.