Chapter 6: Storage
Topic 35

Named Volumes and the Volume Lifecycle

LifecycleVolumes

A named volume has its own lifecycle, fully separate from any container. You create it, containers attach to it, and it persists until you explicitly remove it. That independence is the whole point: Driftwood's driftwood-db-data outlives every db container that ever mounts it, so the database survives restarts, recreations, and image upgrades. The container is the disposable part; the volume is the part you keep.

The trap is the volumes you didn't name. Docker will happily create volumes on your behalf — anonymous ones with random IDs — and those pile up silently until they fill the disk. Understanding the lifecycle is half about the commands that manage named volumes and half about recognizing the anonymous-volume sprawl before /var/lib/docker runs out of space.

Create, Inspect, Remove

The volume commands are a small, predictable set. docker volume create driftwood-db-data makes one. docker volume inspect driftwood-db-data shows its driver and its on-disk mountpoint under /var/lib/docker/volumes. docker volume ls lists every volume on the host, named and anonymous alike. docker volume rm driftwood-db-data deletes one — but only if no container references it. That refusal is a guardrail, not a bug: it is what keeps a live database from being wiped by a stray rm.

The named-volume lifecycle, start to finish
docker volume create driftwood-db-data

docker run -d --name driftwood-db \
  -v driftwood-db-data:/var/lib/postgresql/data \
  postgres:16

docker volume inspect driftwood-db-data
# "Driver": "local", "Mountpoint": "/var/lib/docker/volumes/driftwood-db-data/_data"

docker rm -f driftwood-db          # container gone, volume untouched
docker volume rm driftwood-db-data # now it's safe to remove — nothing references it

The sequence shows the separation in one breath: the volume is created before any container, a container attaches by name, removing the container leaves the volume intact, and the volume only goes away when you ask for it directly. You almost never run docker volume create by hand in practice — a -v driftwood-db-data:/path on first run creates it automatically — but doing it explicitly makes the lifecycle visible.

The named-volume lifecycle
volume create
mount into container
inspect / use
prune --all removes

Volume Lifecycle Is Independent of Containers

Removing a container does not remove its named volumes. docker rm driftwood-db destroys the container and its writable layer, but driftwood-db-data stays exactly where it was. Start a new container from a newer postgres:16 image and mount the same volume, and the new Postgres opens the existing data directory — every bookmark intact. This is the property that makes a named volume the correct home for a database: you upgrade the engine by replacing the container, and the data simply stays put underneath.

Anonymous vs Named Volumes

Mount a volume without giving it a name — -v /var/lib/postgresql/data, a path with no name: in front — and Docker creates a volume with a random 64-character hex ID. It persists on disk exactly like a named volume; the difference is that you can't address it meaningfully. The moment its container is gone, you are left with a long hex string in docker volume ls and no way to tell what it holds. An anonymous volume is durable storage you've immediately lost the handle to.

The VOLUME Instruction Surprise

A base image can declare a VOLUME in its Dockerfile, and the postgres image declares one for its data directory. The effect is that every docker run which doesn't supply a named volume for that path gets an anonymous volume created automatically. Run and remove the container repeatedly — a test loop, a CI job, a developer poking at it — and you accumulate one dangling anonymous volume per run, each holding a full copy of a database. Nothing warns you; docker ps looks clean while /var/lib/docker/volumes quietly grows.

Pruning Reclaims the Orphans

docker volume prune reclaims the anonymous-volume sprawl in one command — by default it removes only the anonymous volumes no container references, leaving unused named volumes alone. That default is a guardrail: naming a volume driftwood-db-data keeps a plain prune from touching it even when it's momentarily unreferenced during a deploy. The danger is docker volume prune --all (or -a), which drops the anonymous filter and will delete an unused named volume just like a stray anonymous one — so an unattached driftwood-db-data is fair game the instant you add that flag. And compose down -v or docker rm -v bypass the question entirely by removing attached volumes on purpose — including driftwood-db-data.

Common Mistakes
  • Relying on an anonymous volume — or the postgres image's VOLUME default — for Driftwood's database, then losing track of which random-ID volume holds the real data once the container is gone; name it driftwood-db-data so it's addressable and survivable.
  • Running postgres:16 repeatedly without --rm and without a named volume, accumulating one dangling anonymous volume per run until /var/lib/docker fills with abandoned database copies.
  • Running docker volume prune --all on a host where a named volume you needed happens to have no container attached at that instant — the --all flag drops the anonymous-only default and removes it, and there is no undo (a plain prune would have spared the named volume).
  • Assuming docker rm -v or compose down -v is harmless cleanup — the -v removes attached volumes, so it deletes driftwood-db-data and the database with it.
  • Trying to docker volume rm a volume still attached to a container and reading the refusal as a bug — it's the guardrail; stop and remove the container first.
Best Practices
  • Name every volume that holds data you keep (driftwood-db-data), so it's addressable, inspectable, and safe from anonymous-volume confusion.
  • Treat the volume as the durable thing and the container as disposable — upgrade Postgres by removing the old container and starting a new one against the same named volume.
  • Schedule docker volume prune on long-lived hosts to reclaim orphaned anonymous volumes, but only after confirming nothing unattached still matters.
  • Never reach for -v on docker rm or compose down unless you genuinely intend to destroy the data, and keep that flag out of routine teardown scripts.
Comparable tools Podman mirrors the create/inspect/rm/prune lifecycle and the same anonymous-volume behavior Kubernetes a PersistentVolumeClaim with its own reclaim policy (Ch12 topic 76) A VM's persistent data disk attached to instances but outliving any one of them

Knowledge Check

What happens to a named volume when you run docker rm on the container using it?

  • The volume stays intact, so a new container can mount it and find the data still there
  • The volume is deleted along with the container's writable layer in the same operation
  • The volume's contents are wiped clean but the empty volume itself remains
  • The volume is renamed to a random 64-character hex ID and silently becomes anonymous, so it survives but you can no longer address it by its old name

Why does an anonymous volume become a problem the moment its container is gone?

  • It persists on disk but has only a random hex ID, so you can't tell what it holds or address it meaningfully
  • Docker deletes it automatically on removal, so any data written to it is lost the instant the container is gone
  • It is RAM-backed, so its contents vanish the moment the container stops or exits
  • It can never be mounted again by another container under any circumstances

How does a base image's VOLUME instruction lead to anonymous-volume sprawl?

  • Each run that doesn't supply a named volume for that path auto-creates a new anonymous volume, one per run
  • It reuses one single shared volume across every run that hits the declared path, so data written by one container quietly leaks into the next and bleeds between otherwise unrelated containers
  • It prevents you from attaching a named volume to that declared path at all
  • It bakes the data directory contents into the image, bloating every push

What does compose down -v remove that docker volume prune would spare?

  • The stack's attached named volumes, including driftwood-db-data, because -v deletes attached volumes on purpose
  • Only the unreferenced anonymous volumes left dangling by the stack's own containers, which a plain docker volume prune would have skipped because it spares everything still in use
  • The images the stack was built from, forcing a full rebuild on next up
  • The contents of the volumes while keeping the now-empty volumes in place

You got correct