skip to content

Volume Lifecycle & Drivers

Volumes as first-class objects: creating, listing, inspecting and pruning them, anonymous volumes left behind by VOLUME, copy-up pre-population from image content, and local vs plugin drivers. Interviewers ask to hear where the data physically lives.

part ofDockeroverview, primer and where to startread it →
on this pageshow

questions

6

Walk through the lifecycle of a Docker named volume: how you create one, how you find out where its data physically lives, how it gets attached to a container, and what happens to the data when that container is deleted.

level: juniorimportance: must knowfreq 70%

answer

  1. create / ls / inspect / rm — four verbs
  2. Mountpoint = /var/lib/docker/volumes/<name>/_data
  3. named survives docker rm; anonymous dies with -v
  4. "volume is in use" → a stopped container still holds it
  5. docker system df -v for size

basics

~20 s

Create with docker volume create name, list with docker volume ls, see its host path and driver with docker volume inspect name, attach with -v name:/path. Named volumes outlive containers: deleting the container leaves the volume until you run docker volume rm.

solid answer

~50 s

A named volume is a storage object managed by the Docker daemon, independent of any container. `docker volume create app-data` creates it; `docker volume ls` lists volumes; `docker volume inspect app-data` shows its driver, options, labels and `Mountpoint` (for the built-in `local` driver, typically `/var/lib/docker/volumes/app-data/_data`). You attach it at run time with `-v app-data:/var/lib/postgresql/data` or the more explicit `--mount type=volume,src=app-data,dst=/var/lib/postgresql/data`; if it does not exist, Docker creates it implicitly. Lifecycle is the key point: the volume is **not** owned by the container. `docker rm` (even `docker rm -v`) does not delete a named volume — only anonymous ones. The data survives container removal, image upgrades and daemon restarts, which is exactly why databases use volumes. You delete it explicitly with `docker volume rm app-data`, and Docker refuses while any container (even a stopped one) still references it.

code

bash · 11 lines
bash
docker volume create app-data
docker volume inspect app-data --format '{{.Driver}} {{.Mountpoint}}'

docker run -d --name db \
  --mount type=volume,src=app-data,dst=/var/lib/postgresql/data \
  -e POSTGRES_PASSWORD=secret postgres:16

docker rm -f db          # volume and data still there
docker volume ls | grep app-data

docker volume rm app-data   # explicit delete

go deeper

for a junior

Know the four commands (create, ls, inspect, rm) and the headline rule: named volumes outlive containers and must be deleted explicitly.

for a middle

Add the distinctions — named vs anonymous under docker rm -v and --rm, -v vs --mount syntax, why volume is in use appears, and what inspect fields mean.

for a senior

Frame it operationally: volumes are the state boundary in a redeploy, disk creep is the real failure mode, docker system df -v and label conventions are how you keep a host inventory manageable.

for a principal

Talk policy — naming and labelling conventions so every volume traces to an owning service, who is allowed to delete state, and the fact that host-local volumes tie a stateful workload to one machine, which constrains your placement and DR story.

## What a named volume actually is A container's writable layer is throwaway: it is created with the container and destroyed with it. A **volume** is a separate, daemon-managed storage object with its own name and its own lifetime. Containers reference volumes; they do not own them. That single sentence explains almost every behaviour below. ## Creating ``` docker volume create app-data ``` This registers a volume with the default driver (`local`) and no options. You rarely have to run it explicitly: if you start a container with `-v app-data:/data` and no such volume exists, the daemon creates it on the spot with default settings. Explicit creation matters when you want to set something at creation time — labels (`--label app=billing`) or driver options — because those cannot be changed later; you would have to remove and recreate the volume. ## Listing and inspecting ``` docker volume ls docker volume ls -f dangling=true # volumes no container references docker volume inspect app-data ``` `inspect` returns JSON with the fields that matter operationally: - `Driver` — which storage plugin manages it (`local` unless you chose otherwise). - `Options` — the driver options captured at creation. - `Mountpoint` — where the data sits for the `local` driver on Linux: `/var/lib/docker/volumes/app-data/_data`. - `Scope` — `local` (this host) or `global` (a cluster-wide plugin). - `Labels`, `CreatedAt`. Treat `Mountpoint` as *diagnostic*, not as an interface. It is a real host path on Linux and you can read it as root, but on Docker Desktop for macOS/Windows the daemon runs inside a Linux VM, so that path does not exist on your laptop. Tooling that pokes at `/var/lib/docker/volumes` directly breaks the moment the driver changes, so it is not the supported way to move data in and out. ## Attaching to a container Two syntaxes, same underlying object: ``` docker run -d -v app-data:/var/lib/postgresql/data postgres:16 docker run -d --mount type=volume,src=app-data,dst=/var/lib/postgresql/data postgres:16 ``` The short `-v` form is terse and ambiguous (the first field is a volume name if it has no slash, a host path if it does). `--mount` is explicit key/value, fails loudly on typos, and is the only way to pass some options (such as `volume-nocopy` or `readonly` in a self-documenting way). Prefer `--mount` in anything you commit. At container start the daemon mounts the volume's directory over the target path inside the container's mount namespace. Anything the image had at that path is hidden by the mount — though for an *empty* volume Docker first copies the image content into it ("copy-up"), which is a separate behaviour worth knowing. Many containers may mount the same volume simultaneously; Docker does no locking, so concurrent writers need an application that tolerates it (two Postgres instances on one data directory will corrupt it). ## Removal — the part interviews test - `docker stop` / `docker rm` on the container: the volume and its data **survive**. - `docker rm -v` (or `docker run --rm`): removes *anonymous* volumes attached to that container; a **named** volume is untouched. - `docker volume rm app-data`: the explicit delete. It fails with "volume is in use" if any container — including a stopped or created-but-never-started one — still references it. `docker ps -a --filter volume=app-data` finds the holder. - `docker compose down`: removes containers and networks but keeps named volumes; `docker compose down -v` removes the volumes the Compose file declares. - `docker volume prune`: bulk-removes unused volumes; on modern Engine versions that means anonymous ones only unless you pass `--all`. Because deletion is always explicit for named volumes, the usual production failure is not data loss but disk creep: volumes from long-gone containers piling up under `/var/lib/docker/volumes`. `docker system df -v` shows per-volume size and is the right first command when a host fills up. ## Why this matters Volumes are the supported way to keep state across the whole reason containers are attractive: replacing a container is routine (new image tag, new config, crash restart), and every replacement destroys the writable layer. Putting the database directory, upload directory or cache on a named volume decouples "the process I redeploy constantly" from "the bytes I must never lose".

  • Why does `docker volume rm` fail for a volume whose container was stopped hours ago?
    A stopped container still exists as a Docker object and still holds its mount references, so the daemon refuses to delete the volume underneath it. Remove or recreate the container first (`docker rm <id>`), then delete the volume. `docker ps -a --filter volume=<name>` lists every container, running or not, that references it.
  • Can you rename or resize a named volume in place?
    No. There is no `docker volume rename`, and driver options such as size or NFS parameters are fixed at creation. The supported path is to create a new volume with the settings you want and copy the data across with a helper container that mounts both, then repoint the workload and delete the old volume.
  • Is reading `/var/lib/docker/volumes/<name>/_data` from the host a legitimate way to work with volume data?
    It is fine for a quick look on a Linux host as root, but it is not a supported interface. The path only exists for the built-in `local` driver, it does not exist at all on Docker Desktop where the daemon runs inside a VM, and writing there bypasses the daemon's bookkeeping. Use a helper container that mounts the volume instead.

A container is a rented apartment; a named volume is the storage unit down the street. Moving out of the apartment (removing the container) does not empty the storage unit — you have to go cancel that contract yourself.

saying these in an interview costs you the question

  • Saying that removing the container removes its named volume — data loss is the opposite of what happens.
  • Believing `docker run --rm` cleans up named volumes; it only removes anonymous ones.
  • Treating `/var/lib/docker/volumes/...` as the API and building backup scripts around it.
  • Thinking a volume must be created before use — Docker auto-creates it on first reference, which is exactly how stray volumes appear.
  • Assuming `docker compose down` wipes the database volume, or that it never does (it does with `-v`).

context

open as a page

A Dockerfile contains the instruction `VOLUME /var/lib/data`. What does the Docker daemon do when someone runs a container from that image, and why do hosts running such images accumulate dozens of unnamed volumes?

level: middleimportance: must knowfreq 58%

basics

~20 s

Every container started from that image gets a fresh anonymous volume (a random 64-hex-character name) mounted at /var/lib/data unless the run command supplies its own mount. Each docker run creates another one, and they are only cleaned up by --rm, docker rm -v or a prune — hence the pile-up.

open as a page

A Docker named volume holds a service's data directory and you need an off-host backup of it, plus a way to restore that backup onto a different machine. How do you take and restore that backup, and what makes the copy trustworthy?

level: middleimportance: should knowfreq 42%

basics

~20 s

Run a throwaway helper container that mounts the volume read-only plus a host directory, and tar the data out: docker run --rm -v vol:/data:ro -v "$PWD":/backup alpine tar czf /backup/vol.tgz -C /data .. Restore by untarring into a fresh volume the same way. Quiesce or dump the service first — a live database copy is not consistent.

open as a page

You mount a brand-new, empty Docker named volume at `/usr/share/nginx/html`, a path that already contains files baked into the image. What does the container see on the first start, what does it see on the second start, and how would the result differ if you mounted a host directory at that path instead?

level: middleimportance: should knowfreq 48%

basics

~20 s

On the first start Docker copies the image's content at that path into the empty volume ("copy-up"), so the container sees the image files. On the second start the volume is no longer empty, so it is mounted as-is — stale content persists. A host bind mount never copies; it simply hides the image files.

open as a page

An engineer ran `docker volume prune` on a busy production host to reclaim disk space. Which volumes does that command actually delete, which does it spare, and how would you reclaim volume space safely on such a host?

level: seniorimportance: should knowfreq 45%

basics

~20 s

It deletes volumes no container references. On Docker Engine 23.0+ that means anonymous ones only by default; --all extends it to unused named volumes — the dangerous flag, since a stopped service's database volume counts as unused. Safe practice: inspect with docker volume ls -f dangling=true and docker system df -v, prune by label, back up first.

open as a page

Docker's built-in `local` volume driver can be given mount options at creation time, and third-party volume plugins can be installed alongside it. Explain what a volume driver is responsible for, what the `local` driver's options let you do, and how you would decide whether a workload needs a plugin driver instead.

level: seniorimportance: nice to knowfreq 33%

basics

~20 s

A volume driver is the plugin that creates, mounts and removes the storage behind a volume. The built-in local driver stores data on the host and accepts mount(8)-style options (type=nfs, type=tmpfs, bind). A plugin driver adds remote or cluster-scoped storage — worth it only when containers must move between hosts and keep their data.

open as a page