Docker & ContainersXXVIII Β· MaintenanceVolume hygiene
Volume lifecycle β orphans, anonymous volumes, and safe reclamation
What you'll learn
- Explain how anonymous volumes are created and why they accumulate
- Audit an unattached volume before deleting it
- Choose between `docker volume prune`, `--all`, and `docker rm -v`
- Recognise the Compose commands that destroy volume data
Prerequisites
Verified against Docker Engine 29.x Β· Docker Engine 28.x Β· Docker Compose 2.x Β· containerd 2.x Β· runc 1.2.x Β· BuildKit 0.20+ Β· Linux kernel 5.15+ Β· Ubuntu 24.04 LTS Β· Debian 12 (Bookworm) Β· 2026-08-11
Run docker volume ls on a host that has been in service for a year and you
get something like this:
$ docker volume lsDRIVER VOLUME NAME
local 0e22ff337fce030ca13101cf85a6c2c5a16adaa1bab461f0f89c15214e3c456e
local 1c2f6c9913f64e83719fab7d85f0d8907acd93d03128f282e1eff4b7345951fc
local 1e4617a57468922d11e5997e605efb7e1fe5da073e7d8d78cf6f4dfa2d7d1ae2
local app_pgdata
local app_redis
local 6c056b1d1212d3a4c04bedb3974990f8f296db5986a00b048770ea64789cf3bcIllustrative output
Two of those names mean something. Four are 64-character hex strings that give no hint of what they hold, when they were created, or whether anything would miss them. Volumes are the only Docker object where guessing wrong destroys data that exists nowhere else, so this is the maintenance task that deserves the most care and usually gets the least.
Where the hex names come from
Those are anonymous volumes. Docker creates one, named after a random identifier, whenever a container needs a volume at a mount point and no name was supplied. Three things do this:
Every time that container is replaced without --rm or docker rm -v, the
old anonymous volume is left behind and a new one is created. A service that
gets redeployed weekly accumulates a volume a week, each holding a stale copy
of a data directory.
Auditing before deleting
Never prune a volume you have not looked at. Three commands do the whole audit.
Which volumes are unattached
docker volume ls --filter dangling=truedangling=true means βnot referenced by any containerβ, running or stopped β
the same population the default prune targets, plus the named ones it will
spare.
How big they are and how many links
$ docker system df -vLocal Volumes space usage:
VOLUME NAME LINKS SIZE
app_pgdata 1 2.11GB
0e22ff337fce030ca13101cf85a6c2c5a16adaa1bab461f0f89c15214e3c456e 0 40.01MB
1c2f6c9913f64e83719fab7d85f0d8907acd93d03128f282e1eff4b7345951fc 0 88B
6c056b1d1212d3a4c04bedb3974990f8f296db5986a00b048770ea64789cf3bc 0 89BIllustrative output
LINKS is the container reference count. LINKS 0 is an orphan candidate.
The size column is the discriminator: an 88-byte volume is a runtime scratch
directory nobody will miss. A 40 MB volume held a real dataset.
What is inside
The only reliable answer. Mount it read-only into a throwaway container:
VOL=0e22ff337fce030ca13101cf85a6c2c5a16adaa1bab461f0f89c15214e3c456e
docker run --rm -v "$VOL":/audit:ro alpine:3.20 sh -c 'ls -la /audit; du -sh /audit'A PG_VERSION file and a base/ directory tells you it is a Postgres data
directory. An empty tree or a single socket file tells you it is disposable.
Two minutes of this beats any amount of reasoning about names.
Choosing the right removal
| Situation | Command | Scope |
|---|---|---|
| Container is being removed and its anonymous volume is junk | docker rm -v CONTAINER | Anonymous volumes of that container only |
| Container is short-lived | docker run --rm ... | Anonymous volumes removed on exit |
| Routine cleanup of orphaned anonymous volumes | docker volume prune | Unattached anonymous volumes |
| Removing a specific volume you have audited | docker volume rm NAME | Exactly that volume |
| Reclaiming unattached named volumes | docker volume prune -a | Unattached volumes of both kinds |
The first two are the ones that prevent the problem rather than cleaning it
up. docker rm -v removes anonymous volumes associated with the container β
it never removes a named one, which is what makes it safe to use by default.
# Removes the container and any anonymous volumes it created
docker rm -v old-worker
# For short-lived containers, do it at run time
docker run --rm -v /scratch alpine:3.20 trueAdopt docker rm -v as the habit and the hex strings stop accumulating.
The Compose commands that delete data
Compose has its own vocabulary here and one of the flags is a data-loss button.
| Command | Containers | Networks | Named volumes | Anonymous volumes |
|---|---|---|---|---|
docker compose stop | Stopped | Kept | Kept | Kept |
docker compose down | Removed | Removed | Kept | Kept |
docker compose down -v | Removed | Removed | Deleted | Deleted |
docker compose down --rmi all | Removed | Removed | Kept | Kept |
docker compose down on its own is safe for data: it removes containers and
networks and leaves the volumes: section alone. -v removes the named
volumes declared in that section β the database, the uploads directory,
whatever the stack persists.
A safe reclamation procedure
# 1. List candidates with sizes
docker system df -v | sed -n '/Local Volumes/,$p'
# 2. Record them
docker volume ls --filter dangling=true --format '{{.Name}}' > /tmp/orphans.txt
# 3. Audit every candidate over a size you care about
while read -r vol; do
echo "== $vol"
docker run --rm -v "$vol":/audit:ro alpine:3.20 sh -c 'du -sh /audit; ls -A /audit | head -5'
done < /tmp/orphans.txt
# 4. Remove only what you decided to remove, by name
# (edit /tmp/orphans.txt first to remove anything you are keeping)
xargs -r -a /tmp/orphans.txt docker volume rmStep 4 uses docker volume rm with an explicit list rather than
docker volume prune, on purpose. The list is a record of a decision. A prune
is a decision made by whatever the host looked like at that instant, including
any container that happened to be removed thirty seconds earlier.
Knowledge check
Knowledge check Β· 4 questions
Q1. You run `docker run -d --name db postgres:16` with no volume flags. What happens to the database data directory?
Q2. Which column in `docker system df -v` tells you whether a volume is currently referenced by a container?
Q3. Which commands can delete the contents of a NAMED volume? Select all that apply.
Q4. A volume attached to a stopped container can be removed by `docker volume rm` because the container is not running.
Passing score: 75%. Answers are checked in this browser.