docker volumeManage persistent data for containers
docker volume manages named volumes: storage that lives outside any container's writable layer, so data survives docker rm, upgrades and re-creation. Databases, uploads and anything you'd cry about losing belong in a volume (or a bind mount), never in the container.
docker volume ls | create | inspect | rm | prune [OPTIONS]You want to prove to yourself that data written to a volume survives deleting the container.
docker run -d --name dbVolumes are usually created implicitly when a container mounts one by name.
A named volume with the default local driver is a directory under /var/lib/docker/volumes/<name>/_data. When a container starts, dockerd bind-mounts that directory into the container's mount namespace at the target path, so reads and writes bypass the overlay filesystem entirely: no copy-on-write, full disk speed. The volume is a separate, reference-counted object: removing a container never removes a named volume, and docker volume rm refuses while any container (even a stopped one) uses it. The first time an empty named volume is mounted over a path that has files in the image, Docker copies those files in; bind mounts never do. Other drivers (NFS options on local, or plugins) put the data on network storage instead of the host disk.
lsList volumes (-f dangling=true for unused ones)create NAMECreate a volume explicitly (-d driver, -o driver options, --label)inspect NAMEDriver, mountpoint on the host, labels, creation timerm NAMEDelete a volume and all its data (refused while in use)pruneDelete unused anonymous volumes; -a also deletes unused named ones-v NAME:/path[:ro]Mount a named volume (on docker run)-v /host/path:/pathBind-mount a host directory instead--tmpfs /pathIn-memory mount, gone when the container stopsRunning a database without -v and upgrading with docker rm + docker runThe data was in the container's writable layer (or an anonymous volume you then lose track of) and is gone with the container.
docker run -v pgdata:/var/lib/postgresql/data postgres:16 from day onedocker volume prune -a (or system prune -a --volumes) on a serverRemoves every volume no container is using right now, including databases whose container is briefly removed during an upgrade.
List with docker volume ls -f dangling=true, then remove by nameCopying /var/lib/docker/volumes/<db>/_data while the database runsA file-level copy of a live database is usually inconsistent and may not restore.
pg_dump/mysqldump, or stop the container before the file backupBind-mounting a host folder and getting 'permission denied' insideThe container runs as a uid (e.g. 999 for postgres) that doesn't own the host directory.
chown the host dir to the container's uid, or use a named volumeTry these on a Linux machine of your own. Each task has a hint and a solution.
Back up the appdata volume (create it and write a file into it first) to ~/backups/appdata-<today>.tgz with a throwaway alpine container, then list what's inside.
Write the docker command that restores ~/backups/pgdata.tgz into a new empty volume pgdata2.
Write the command that lists only volumes not used by any container.
docker volumeManage persistent data for containers
docker volume manages named volumes: storage that lives outside any container's writable layer, so data survives docker rm, upgrades and re-creation. Databases, uploads and anything you'd cry about losing belong in a volume (or a bind mount), never in the container.
docker volume ls | create | inspect | rm | prune [OPTIONS]You want to prove to yourself that data written to a volume survives deleting the container.
docker run -d --name dbVolumes are usually created implicitly when a container mounts one by name.
A named volume with the default local driver is a directory under /var/lib/docker/volumes/<name>/_data. When a container starts, dockerd bind-mounts that directory into the container's mount namespace at the target path, so reads and writes bypass the overlay filesystem entirely: no copy-on-write, full disk speed. The volume is a separate, reference-counted object: removing a container never removes a named volume, and docker volume rm refuses while any container (even a stopped one) uses it. The first time an empty named volume is mounted over a path that has files in the image, Docker copies those files in; bind mounts never do. Other drivers (NFS options on local, or plugins) put the data on network storage instead of the host disk.
lsList volumes (-f dangling=true for unused ones)create NAMECreate a volume explicitly (-d driver, -o driver options, --label)inspect NAMEDriver, mountpoint on the host, labels, creation timerm NAMEDelete a volume and all its data (refused while in use)pruneDelete unused anonymous volumes; -a also deletes unused named ones-v NAME:/path[:ro]Mount a named volume (on docker run)-v /host/path:/pathBind-mount a host directory instead--tmpfs /pathIn-memory mount, gone when the container stopsRunning a database without -v and upgrading with docker rm + docker runThe data was in the container's writable layer (or an anonymous volume you then lose track of) and is gone with the container.
docker run -v pgdata:/var/lib/postgresql/data postgres:16 from day onedocker volume prune -a (or system prune -a --volumes) on a serverRemoves every volume no container is using right now, including databases whose container is briefly removed during an upgrade.
List with docker volume ls -f dangling=true, then remove by nameCopying /var/lib/docker/volumes/<db>/_data while the database runsA file-level copy of a live database is usually inconsistent and may not restore.
pg_dump/mysqldump, or stop the container before the file backupBind-mounting a host folder and getting 'permission denied' insideThe container runs as a uid (e.g. 999 for postgres) that doesn't own the host directory.
chown the host dir to the container's uid, or use a named volumeTry these on a Linux machine of your own. Each task has a hint and a solution.
Back up the appdata volume (create it and write a file into it first) to ~/backups/appdata-<today>.tgz with a throwaway alpine container, then list what's inside.
Write the docker command that restores ~/backups/pgdata.tgz into a new empty volume pgdata2.
Write the command that lists only volumes not used by any container.