sehaj/learn
Docker/04 Data

04.02 · with code · 12 min

Volumes

Named storage that Docker manages and that outlives any container: create it, mount it, share it, back it up, and avoid the anonymous kind.

The core idea

A volume is a directory that Docker creates and manages, separate from any container. You mount it into a container at a path, and everything written there goes into the volume. Remove the container and the volume stays; mount it into a new container and the data is all there.

Create, write, read again

❯terminal
$ docker volume create notes-data
notes-data
$ docker run --rm -v notes-data:/data alpine sh -c 'echo "written by container one" > /data/hello.txt'
$ docker run --rm -v notes-data:/data alpine cat /data/hello.txt
written by container one

Two containers, both deleted with --rm. The file lives on in the volume.

❯terminal
$ docker volume inspect notes-data
[
{
"CreatedAt": "2026-11-02T20:30:51Z",
"Driver": "local",
"Mountpoint": "/var/lib/docker/volumes/notes-data/_data",
"Name": "notes-data",
"Scope": "local"
...
}
]

The Mountpoint is a folder on the Docker host. On Linux you could look at it directly with sudo; on Docker Desktop it's inside the Linux VM. Either way, treat it as Docker's: go through containers, not the folder.

Two ways to write the same mount

mount syntax
# Short: source:destination[:options]
docker run -v notes-data:/data alpine ...

# Long: explicit key=value pairs, easier to read in scripts
docker run --mount type=volume,src=notes-data,dst=/data alpine ...

Add :ro (short) or ,readonly (long) to mount read-only:

❯terminal
$ docker run --rm --mount type=volume,src=notes-data,dst=/data,readonly alpine \
sh -c 'cat /data/hello.txt; echo nope > /data/x'
written by container one
sh: can't create /data/x: Read-only file system

Named vs anonymous volumes

If an image declares VOLUME /some/path and you don't mount anything there, Docker creates an anonymous volume with a random name. The official Postgres image does this:

❯terminal
$ docker run -d --name pg -e POSTGRES_PASSWORD=x postgres:18
$ docker inspect -f '{{range .Mounts}}{{.Type}} {{.Name}} -> {{.Destination}}{{end}}' pg
volume 0eb4d36e933db0246a63ef9175338b25d3d8940343647a3981762d657c662acd -> /var/lib/postgresql

Your data is safe-ish, but in a volume nobody will recognise. Recreate the container and you get a new anonymous volume and an empty database; the old one sits there orphaned. docker rm -v and docker run --rm delete anonymous volumes along with the container. Always name volumes for data you care about.

Pre-populated volumes

Mount an empty named volume at a path that already has files in the image, and Docker copies those files into the volume first:

❯terminal
$ docker run --rm -v site:/usr/share/nginx/html nginx:alpine ls /usr/share/nginx/html
50x.html
index.html
$ docker run --rm -v site:/x alpine ls /x
50x.html
index.html

The second container is plain Alpine, but the volume already contains nginx's files. This only happens for empty volumes, never for bind mounts (04.03 Bind mounts).

Backing up a volume

A volume is just files, so back it up with a throwaway container that mounts it next to a folder from your machine:

❯terminal
$ docker run --rm -v notes-data:/data -v "$PWD":/backup alpine \
tar czf /backup/notes-data.tgz -C /data .
$ tar tzf notes-data.tgz
./
./hello.txt

To restore, run the same thing with tar xzf into a new volume. For databases, prefer the database's own dump tool, because copying the files of a running database can capture a half-written state (04.05 Project: persist Postgres).

Housekeeping

CommandDoes
docker volume lslist volumes
docker volume ls -f dangling=truevolumes no container uses
docker volume rm NAMEdelete one (fails if a container uses it)
docker volume prunedelete unused anonymous volumes; add -a to include named ones
docker system df -vsize of each volume
Predict first

Three containers mount the same named volume at /data. One deletes /data/report.csv. What do the other two see?

Commit to an answer before you read on.
CheckpointMake data outlive its containers

Create a volume, write to it from one container, read it from another, then back it up to a .tgz on your machine. Delete the volume, restore it from the archive into a new volume, and read the file once more.

STUCK? ▸

Empty volume when you expected files: check the volume name is spelled the same in both commands. -v notes-dat:/data silently creates a new, empty volume called notes-dat.

Recap

Interview questions

MidfreqMust-knowConcept

What's the difference between a named volume and an anonymous volume?

MidfreqGood to knowScenario

How would you back up and restore data stored in a Docker volume?

Report a mistakeEdit this page
☰ Data04.02 · 23/44next →