Practical Linux, Windows Server and cloud guides for IT pros.

Docker Disk Space Full: Clean Up Images, Cache and Logs Safely

Find what fills Docker storage, remove selected disposable objects, protect volumes and control logs. Includes an isolated before-and-after cleanup test.

Filed under

, ,

Published

Written by

Last updated

Safe Docker disk cleanup sequence: inventory storage, remove one reviewed object, then verify persistent data survives.

When Docker reports “no space left on device”, do not start with a blanket prune. First identify the full filesystem and the type of data consuming it. An unused image, a container’s writable layer, a runaway log and a database volume need different decisions.

The safest useful cleanup is usually an exact object you have identified as disposable. “Reclaimable” in Docker’s output means Docker can remove something under the command’s rules. It does not mean your team no longer needs it.

TL;DR

  • Confirm the daemon, filesystem and inode pressure before deleting anything.
  • Use Docker inventories to separate images, layers, cache and volumes.
  • Remove exact stopped containers only after reviewing their data.
  • Treat volumes as persistent application data, even when detached.
  • Set log limits for replacement containers and verify the application afterwards.

Start here: take the inventory below. If the whole Linux filesystem is full, the Linux disk-space guide covers non-Docker causes too.

Space consumerRead-only checkCleanup decision
Images and shared layersdocker system df -vRemove only unneeded image references
Stopped container writable layerdocker ps -a --sizePreserve required files before removing container
Build cachedocker buildx duChoose the builder and retention policy
Container logsInspect logging driver and optionsApply rotation when recreating the service
Persistent volumesdocker volume inspectBack up and establish ownership before deletion
Safe Docker disk cleanup sequence: inventory storage, remove one reviewed object, then verify persistent data survives.

Confirm where Docker is writing

docker context show
docker info --format 'Root={{.DockerRootDir}} Driver={{.Driver}} Logging={{.LoggingDriver}}'
docker system df -v
docker ps -a --size

These commands query the selected daemon. If the context targets another machine, running df on your laptop does not measure that machine’s disk. On Docker Desktop, the daemon normally writes inside a managed VM disk. Space reclaimed there is not necessarily returned immediately to the host filesystem.

On a native Linux Engine host, use the Docker root directory reported above as the target for df. The path below is the common default, not a guarantee:

df -h /var/lib/docker
df -i /var/lib/docker

The first checks filesystem capacity; the second checks inode exhaustion. A filesystem can have free bytes but no spare inodes for new files. Conversely, Docker can consume storage beyond its reported root: a containerd image store and bind-mounted application directories may live elsewhere. Trace the actual mount rather than adding unrelated numbers together.

Docker Engine 29 and later use the containerd image store by default for fresh installations; upgraded installations can retain classic storage drivers. Docker’s storage guidance explains the distinction. Do not switch drivers as an emergency cleanup: existing objects can become inaccessible.

Understand what the inventory does not tell you

Image sizes overlap because images can share layers. Deleting one tag may reclaim little or nothing while another image or container still references those layers. The writable size of a container does not include the application data held in its mounted volumes or bind mounts.

A stopped container can still contain the only copy of an export or debugging artefact. A detached volume can still contain last month’s database. Check the owner, retention requirement and recovery path before treating either as waste. Do not use a filename or age alone as proof that data is disposable.

Remove one reviewed stopped container

Choose an exact container name from the inventory. Inspect its state and mounts before removing it. This example uses old-test-job as a placeholder; replace it with the object you have reviewed.

docker inspect --format 'Status={{.State.Status}} Mounts={{json .Mounts}}' old-test-job
docker container diff old-test-job

The diff lists changed paths in the writable layer, not the contents of volumes. Copy out anything required and verify that copy before deletion. Avoid sharing inspect output without review: paths and metadata may disclose operational details.

docker container rm old-test-job

There is deliberately no force flag and no volume-removal flag. Removing the stopped container deletes its writable layer, configuration and associated container log; it does not constitute a backup. If removal refuses because the container is running, stop and establish why it is still active rather than adding -f.

Treat images and build cache as separate cleanup jobs

For an image, review its repository, tag and ID, then remove the exact reference only when you no longer need it for running services or rollback. Docker may refuse an image still used by a container. That is useful information, not an obstacle to bypass with force.

docker image ls --digests
docker image rm example/test-image:old

The image reference is illustrative. Do not copy it as a universal cleanup command. For build cache, first identify the builder; a local default builder and a remote Buildx builder are different stores.

docker buildx ls
docker buildx du

Once you have selected the intended builder, docker buildx prune --filter "until=168h" offers an age-filtered cleanup with confirmation. It removes eligible cache, not a preview-only list. Read the prompt and check your builder’s supported options. Rebuilding can require network access and take longer after cache removal.

Avoid docker system prune -a --volumes as a first response. It combines several deletion decisions, including stopped containers and unused data. Docker’s pruning reference documents the individual scopes; use the narrow operation that matches your inventory.

Fix log growth at the source

docker inspect --format '{{json .HostConfig.LogConfig}}' myapp
docker inspect --format '{{.LogPath}}' myapp

Substitute the affected container. An empty log path can be normal for a different logging driver; it does not prove no logs exist. The default json-file driver can grow without rotation unless limits are set. Logs written by the application into a volume are separate from captured stdout and stderr.

For a newly created test container, explicit json-file rotation options look like this. The example runs an isolated disposable BusyBox process and does not change an existing service:

docker run --rm --name log-limit-example \
  --log-driver json-file \
  --log-opt max-size=10m --log-opt max-file=3 \
  busybox:1.37 echo "rotation options configured"

For a real service, put the equivalent settings in its Compose or deployment configuration, preserve any logs required for investigation, and recreate it in an agreed maintenance window. Changing daemon defaults does not retrofit existing containers. The logging driver documentation covers defaults and per-container configuration.

Do not manually delete or truncate Docker-managed log files while the daemon owns them. Docker warns against external manipulation of those files. If the disk is too full to perform controlled maintenance, free known disposable non-Docker data or extend capacity first, then fix the service’s logging behaviour.

Protect volumes and bind-mounted data

docker volume ls
docker volume inspect project_database
docker ps -a --filter volume=project_database

The volume name is a placeholder. Review containers in every state, not just running ones. Establish which application owns the volume and whether there is a tested backup. A raw copy of files from a running database may not be a consistent backup; use that database’s documented backup procedure.

A bind mount lives at a host path and is not cleaned by volume prune. If that path is full, apply the application’s retention rules. Never manually remove files from Docker’s storage directories or delete a database directory simply because it is large.

The isolated cleanup test

On 8 September 2026 I created a fresh Docker-in-Docker daemon, with no host bind mounts, host socket or published ports. A BusyBox container wrote a 16 MiB fixture into its writable layer and exited. A separate named volume held a marker file. Only the exact stopped fixture container was then removed.

CheckBefore removalAfter removal
Disposable container writable layer16.8 MB reported by DockerContainer absent
Named persistent volumeMarker file presentSame marker readable
Other workstation containersOutside the test daemonUntouched

Docker’s writable-layer accounting fell as expected while the named volume survived. This validates the selective removal path, not a promise that every 16 MiB file returns precisely 16 MiB to every filesystem. Shared layers, allocation and Docker Desktop’s VM disk affect the host-visible result. The lab and its anonymous volumes were removed afterwards.

Verify capacity and application health

docker system df -v
docker ps -a --size

Repeat the same filesystem and inode checks on the actual daemon host. Then check application health, database access and the operation that originally failed. Keep the before-and-after inventory with the change record. More free space is not a successful recovery if a service has lost its data.

Set separate retention limits for build cache, logs, application exports and backups. Monitor both disk capacity and inodes, and leave enough headroom for image pulls and deployments. If storage grows again immediately, identify the writer rather than scheduling a broader deletion.

Related: Docker command reference explains objects and flags; installing Docker on Ubuntu covers the host baseline.

Did this solve it?

Leave a Reply

Your email address will not be published. Required fields are marked *

Find more on the site

Keep reading by topic.

If this post was useful, the fastest way to keep going is to pick the topic you work in most often.

Want another useful post?

Browse the latest posts, or support TurboGeek if the site saves you time regularly.