Docker is a platform for developing, shipping and running applications in isolated, lightweight and portable containers. It is a critical part of a developer’s toolbelt and one I use just about everyday.

Docker can consume a large amount of disk space. Per the Docker documentation:

Docker takes a conservative approach to cleaning up unused objects (often referred to as “garbage collection”), such as images, containers, volumes, and networks: these objects are generally not removed unless you explicitly ask Docker to do so. This can cause Docker to use extra disk space.

The problems you might encounter with high disk usage include:

  • Poor system performance
  • System crashes
  • Inability to install new software, update existing software or download files

One solution for reducing Docker hard drive utilization is the prune command.

Docker disk free command

Use the docker system df command to show Docker disk usage. Note, df stands for “disk free”.

$ docker system df
TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          31        2         12.86GB   12.41GB (96%)
Containers      2         2         63B       0B (0%)
Local Volumes   27        2         4.404GB   4.355GB (98%)
Build Cache     244       0         6.249GB   6.249GB

The “Active” column represents objects that are associated with running containers. You can see detailed information using the --verbose flag, such as which objects are active, when they were created and how long they have been running.

Docker is eating up roughly 23.5 GB of storage capacity. 23 GB of that is reclaimable (or unused). Yikes! Let’s free that up.

Docker prune command

Docker comes with a system prune command to remove unused objects. It doesn’t touch active objects. I use it with a few options:

docker system prune --all --force --volumes
  • --all removes all unused images, not just dangling images. A dangling image is one that is not tagged and is not referenced by any container. All images can be rebuilt or pulled from Docker Hub so deleting them is fine.

  • --force bypasses the confirmation prompt.

  • --volumes instructs Docker to delete all unused volumes. This is the one option you need to be careful with. If you want to keep some volumes, see the Exclude objects from pruning section below.

Let’s run it:

$ docker system prune --all --force --volumes
Deleted Volumes:
demo-app_postgres_data
74c2f2d5dac8563407e55bad36183c962434d17ad76cffbcbf2d8aa4678352b9
...

Deleted Images:
untagged: python:latest
untagged: node:19-alpine
deleted: sha256:2ce4f03f420bf05ff5d798bb0fd6900278935328879cf598c9ee815322853b94
...

Deleted build cache objects:
ihpjhn3qh07x8nxg1ex5j1v8i
cwoa38utb7dg9ehcgegaj7p11
...

Total reclaimed space: 19.99GB

We’ve freed up ~20 GB of disk space! Now let’s view Docker’s disk usage:

$ docker system df
TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          2         2         451.7MB   0B (0%)
Containers      2         2         63B       0B (0%)
Local Volumes   2         2         49.69MB   0B (0%)
Build Cache     0         0         0B        0B

The only remaining objects are those linked to running containers.

Exclude objects from pruning

You have a few options to exclude objects from being cleaned up. Let’s review them.

Activate the object

One approach is to activate the object. As demonstrated above, active objects are not pruned. You can see which objects are active via the docker system df --verbose command.

Exclude by object name

You can filter objects by name. Unfortunately docker system prune does not support this filter so you’ll need to use other Docker commands. For example, the following commands remove all volumes except for a select few:

# Remove all volumes except 'volume-name'
docker volume rm $(docker volume ls -q | grep --invert-match 'volume-name')

# Remove all volumes except 'volume-name1' and 'volume-name2'
docker volume rm $(docker volume ls -q | grep --invert-match --extended-regexp 'volume-name1|volume-name2')

Label objects

Docker object labels are a clever approach to protect objects from being pruned.

Label objects in docker-compose.yaml:

services:
  my_app:
    image: nginx
    labels:
      - 'keep'

volumes:
  my_volume:
    labels:
      - 'keep'

Prune objects except for those with the keep label:

docker system prune --all --force --volumes --filter "label!=keep"

In this example, neither my_app nor my_volume will be deleted.

Note, object labels are immutable. To modify labels you must recreate the object.

Takeaways

Here are some key takeaways for effectively managing your Docker disk space.

Clean up unused objects during development

Reduce the rate at which disk space grows by deleting unused objects while you work.

  • Use the --rm flag when starting a container, unless you need the container after it has been stopped, which should be uncommon. One of Docker’s recommended best practices is to create ephemeral containers, which means containers should be designed to be stopped and deleted. For example, if your container creates a file, write it to cloud storage (e.g. S3, Google Drive) instead of the container’s local file system so the file isn’t deleted with the container.
  • Use docker compose down instead of docker compose stop. Both commands stop running containers. The former also removes the containers and any associated network objects. You can take down one step further and add the --volumes flag to prune all linked volumes.

Monitor Docker disk usage and prune often

Use the docker system df command to monitor Docker disk usage. If the total utilization is high, run the prune command.