How it works
The explanation, with examples you can run.
Three kinds of mount
| Type | Where the data lives | Typical use |
|---|---|---|
| Volume | Docker's storage area (/var/lib/docker/volumes/<name>/_data on Linux, inside the VM on Docker Desktop) | Databases, uploads, anything the app owns |
| Bind mount | A path you choose on the host | Source code and config in development, host files a tool must read |
| tmpfs | Memory only | Scratch space, files that must never touch disk |
Volumes survive containers
docker volume create appdatadocker run --rm -v appdata:/data alpine:3.22 sh -c 'echo first > /data/note.txt'docker run --rm -v appdata:/data alpine:3.22 cat /data/note.txt# first docker volume inspect appdata --format '{{.Mountpoint}}'# /var/lib/docker/volumes/appdata/_dataBoth containers were removed (--rm), and the file outlived them. The longer form --mount type=volume,src=appdata,dst=/data says the same thing more explicitly and fails loudly on typos; -v silently creates a new volume if the name is misspelt.
When a new, empty volume is mounted over a directory that has files in the image, Docker copies those files into the volume first. A volume that already has content simply hides what the image had at that path, and so does a bind mount, always.
Bind mounts are for development
docker run --rm -it -v "$PWD":/app -w /app -p 127.0.0.1:8765:3000 node:22-alpine node server.jsEdits on the host show up in the container immediately, which is what live reload needs. The downsides: the container depends on the host's directory layout, file ownership is the host's numeric UID (a non-root container user may not be able to write), the container can modify host files, and on Docker Desktop every access crosses the VM's file sharing. Add :ro when the container only needs to read.
Habits for state
- One owner per volume. Two database containers writing to one volume will corrupt it; shared filesystems need software designed for them.
- Declare volumes in Compose so they are created and named predictably;
docker compose downkeeps them,down -vdeletes them. - Back up through a container. Mount the volume and a host directory into a short-lived container and run
tar, or better, use the database's own dump tool. - Know the
VOLUMEinstruction. AVOLUME /dataline in an image makes Docker create an anonymous volume there for every container that does not mount one; these pile up unnoticed (docker volume ls). - Watch permissions. Pre-create directories with the right owner in the Dockerfile (
RUN mkdir /data && chown node:node /data) so a non-root user can write to a fresh volume.
In Kubernetes the same idea becomes PersistentVolumes and PersistentVolumeClaims: storage with its own lifecycle, attached to whichever pod needs it.
Check yourself
3 questions. Get them all right to finish this topic.
0 of 3 right so far. Get all three to finish this topic.