Back
3/4

Cleanup & Maintenance

+20 XP on completion

#Cleanup & Maintenance

After this lesson you'll know:

  • how to analyze and free disk space
  • what docker system prune really does (and doesn't)
  • how to automate Docker cleanup
  • which tools exist for image analysis

#The Docker Garbage Problem

Docker accumulates garbage over time:

  • Stopped containers — after every docker run without --rm
  • Unused images — old versions after docker build
  • Orphaned volumes — forgotten data after docker rm -v
  • Build cache — can grow to gigabytes after a few weeks

If you never clean up, you'll eventually hit a full disk — and Docker will refuse to pull new images.

#Analyze First: docker system df

Before you delete, analyze:

# Overview
docker system df

# TYPE           TOTAL   ACTIVE  SIZE        RECLAIMABLE
# Images         12      5       2.345GB     1.2GB (51%)
# Containers     8       3       45MB        25MB (55%)
# Local Volumes  6       2       890MB       680MB (76%)
# Build Cache    -       -       420MB        420MB (100%)

# Detailed view with layers (very revealing!)
docker system df -v
# Shows every image, container, and volume individually

docker system df is your first step when you run into disk space issues. It tells you exactly where the waste is.

šŸ’” The RECLAIMABLE column is gold. That's the space you can free immediately by cleaning up.

#The Big Gun: docker system prune

# The nuke (CAUTION!)
docker system prune -a --volumes

# This deletes: all stopped containers, unused images,
# all volumes without a running container, build cache
# āš ļø Volumes with important data will be deleted! Only use --volumes
# when you're sure all volumes are expendable.

The safe way — start without --volumes:

docker system prune -a --filter "until=24h"
# Only deletes things older than 24h. Great for weekly routines.

The --filter parameter is gold. It lets you only delete what's truly old — keeping today's images safe.

#Targeted Cleanup (the safe way)

# Stopped containers only
docker container prune

# Unused images only (older than 24h)
docker image prune -a --filter "until=24h"

# Orphaned volumes only
docker volume prune

# Build cache only (safe — gets rebuilt)
docker builder prune

# Keep certain images (delete all except postgres or nginx)
docker image prune -a --filter "reference!=postgres" --filter "reference!=nginx"

#Automated Cleanup with Cron

Why clean manually when your computer can do it?

# Once a week, Sunday at 3 AM
# crontab -e:
0 3 * * 0 docker system prune -af --filter "until=24h" >/dev/null 2>&1

# Once a month also volumes (careful — only if no critical data stored)
0 4 1 * * docker system prune -af --volumes --filter "until=168h" >/dev/null 2>&1

With --filter "until=24h" you ensure freshly built images aren't deleted. Perfect for CI servers or dev machines.

Docker built-in log rotation:

# Start Docker with limited logs (in daemon.json)
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

Without this config, a few weeks of container logs can fill your disk. A container logging 100 lines/second writes ~30 GB per week. With rotation to 3Ɨ10 MB, it's capped at 30 MB.

#Image Size Analysis

# All images with sizes
docker images

# Layer-by-layer analysis of a specific image
docker history my-app:latest
# IMAGE          CREATED       CREATED BY                                      SIZE
# abc123         2 min ago     COPY . .                                        2.5MB
# def456         2 min ago     RUN npm run build                               245MB
# ghi789         3 min ago     COPY --from=builder /app/dist ./dist            1.2MB
# ...

# Layer sizes only
docker history --no-trunc my-app | awk '{print $1, $NF}'

docker history shows every layer with its size. This is the secret weapon to identify oversized images: "Why is my image 500 MB? Because RUN npm install installed all devDependencies and I never cleaned up the layer."

External tool: [dive](https://github.com/wagoodman/dive) — analyzes image layers interactively.

dive my-app:latest
# Shows layer contents + space waste directly

#Keeping Build Cache Under Control

# Check cache size
docker builder prune --all --keep-storage 2GB 2>/dev/null; docker system df | grep Build

# Limit cache to 2 GB (during prune)
docker builder prune --all --keep-storage 2GB

# Or globally in /etc/docker/daemon.json
{
  "builder": {
    "gc": {
      "enabled": true,
      "keepStorage": "2GB",
      "defaultKeepStorage": "200MB"
    }
  }
}

# Complete build cache wipe (for CI/systemd timers)
docker builder prune -af

The build cache is the biggest hidden space hog. Especially on CI servers or when you build regularly. The global config limits it permanently — set it once, forget it.

#Checklist: Survival Routine

  • Daily: docker system df — a quick glance is enough
  • Weekly: docker image prune -a --filter "until=24h" — old builds gone
  • Monthly: docker volume prune — orphaned volumes
  • As needed: docker builder prune — when cache gets too large
  • One-time: Enable log rotation in /etc/docker/daemon.json

#āœ‹ Try it out

  • docker system df — show how much space Docker is using. Also try -v
  • docker image prune -a --filter "until=24h" — delete only old unused images
  • docker history alpine:latest — inspect the layers of a slim image (only ~7 MB!)
  • docker builder prune --all --keep-storage 500MB — cap cache at 500 MB

#šŸ“Œ Summary

  • docker system df before deleting — analyzing is half the job
  • --filter 'until=24h' makes prune safe for daily use
  • Log rotation in daemon.json prevents full disks from logs
  • Build cache can eat gigabytes — builder prune keeps it in check
  • Automated cleanup via cron = set it once, forget it
← → to navigate