Volume Backups

Volume Drivers and Backing Up Volume Data

A volume driver decides where a volume's data really lives. The built-in local driver accepts the same options as the Linux mount command, so it can mount NFS or CIFS shares or tmpfs as named volumes. Docker 514 's documentation mounts an NFS export with --opt type=nfs --opt o=addr=10.0.0.10 --opt device=:/var/docker-nfs (not run here: this machine has no NFS server). A tmpfs-backed named volume shows the mechanism:

The local driver with mount optionsShell
docker volume create --driver local \
  --opt type=tmpfs --opt device=tmpfs --opt o=size=64m l3-scratch
docker run --rm -v l3-scratch:/s alpine:3 sh -c 'df -h /s | tail -1'
docker volume rm l3-scratch >/dev/null
Output
l3-scratch
tmpfs                    64.0M         0     64.0M   0% /s

Third-party plugins, installed with docker plugin install, add backends such as cloud object storage (rclone/docker-volume-rclone (https://github.com/rclone/rclone 59,978 ), MIT) or network block devices; in Kubernetes 5,150 , CSI drivers (Kubernetes) replaced most of them.

A volume has no built-in backup command. The portable technique mounts it read-only into a throwaway container beside a host directory and runs tar; restoring reverses the direction into a new volume. Stop PostgreSQL 1,289 first so the files are consistent:

Backing up the PostgreSQL volume and restoring it into a new oneShell
mkdir -p ../backups; B="$(realpath ../backups)"
docker stop l3-db >/dev/null
docker run --rm -v l3-pgdata:/data:ro -v "$B":/backup alpine:3 \
  tar czf /backup/pgdata.tgz -C /data .
docker start l3-db >/dev/null
docker volume create l3-pgrestore >/dev/null
docker run --rm -v l3-pgrestore:/data -v "$B":/backup alpine:3 \
  tar xzf /backup/pgdata.tgz -C /data
docker run -d --name l3-db2 --env-file ../booknest.env -v l3-pgrestore:/var/lib/postgresql \
  postgres:18 >/dev/null
sleep 4; docker exec l3-db2 psql -U booknest -tAc "SELECT title, price FROM books WHERE id = 3"
docker exec l3-db pg_dump -U booknest booknest | gzip > "$B/booknest.sql.gz"
ls -lh "$B"
docker system df -v | grep -E '^VOLUME NAME|^l3-pg'
Output
Salt and Saffron|19.99
total 6.6M
-rw-r--r-- 1 dev  dev  1.3K Sep 25 18:39 booknest.sql.gz
-rw-r--r-- 1 root root 6.6M Sep 25 18:39 pgdata.tgz
VOLUME NAME                                                        LINKS     SIZE
l3-pgdata                                                          1         48.44MB
l3-pgrestore                                                       1         48.44MB

The restored volume started a second, identical database. Note the two backups' sizes and owners: the file-level archive holds the whole 48 MB cluster (6.6 MB compressed) and belongs to root, because tar ran as root in the container, while pg_dump's logical dump of six books is 1.3 KB and also loads into a newer PostgreSQL release. For databases, prefer the database's own dump tool, and use volume archives for everything else. docker system df -v reports each volume's size and how many containers use it (LINKS); a volume with no links is dangling, and docker volume ls --filter dangling=true lists those candidates for removal.