Why Docker Volumes Matter
Why Docker Volumes Matter
Container filesystems are ephemeral. When a container is removed, all data written to its writable layer is lost. Docker volumes solve this by persisting data outside the container lifecycle.
The Problem
# Start a database container
docker run -d --name pg1 -e POSTGRES_PASSWORD=secret postgres:16
# Create data inside
docker exec pg1 psql -U postgres -c "CREATE TABLE users (id INT, name TEXT);"
docker exec pg1 psql -U postgres -c "INSERT INTO users VALUES (1, 'Alice');"
# Stop and remove container
docker stop pg1 && docker rm pg1
# All data is GONE. The users table no longer exists.
# Starting a new container creates a fresh, empty database.
The Solution
# Start with a named volume
docker run -d --name pg2 \
-e POSTGRES_PASSWORD=secret \
-v pgdata:/var/lib/postgresql/data \
postgres:16
# Create data
docker exec pg2 psql -U postgres -c "CREATE TABLE users (id INT, name TEXT);"
docker exec pg2 psql -U postgres -c "INSERT INTO users VALUES (1, 'Alice');"
# Stop and remove container
docker stop pg2 && docker rm pg2
# Start new container with SAME volume
docker run -d --name pg3 \
-e POSTGRES_PASSWORD=secret \
-v pgdata:/var/lib/postgresql/data \
postgres:16
# Data persists! Query the users table
docker exec pg3 psql -U postgres -c "SELECT * FROM users;"
# id | name
# ----+-------
# 1 | Alice
Volume Storage Location
Docker volumes are stored on the host filesystem, managed by Docker:
# Default location (Linux)
/var/lib/docker/volumes/
# List volumes
docker volume ls
# Inspect a volume
docker volume inspect pgdata
# {
# "Mountpoint": "/var/lib/docker/volumes/pgdata/_data",
# "Driver": "local",
# "Name": "pgdata"
# }
The data lives at /var/lib/docker/volumes/pgdata/_data on the host. If the Docker host dies, the data is lost unless backed up. For critical data, use cloud-backed volume drivers.
Volume Operations
Volume Operations
Creating Volumes
# Create a named volume
docker volume create mydata
# Create with driver options
docker volume create --driver local \
--opt type=none \
--opt device=/data \
--opt o=bind \
myvolume
Using Volumes with Containers
# Mount a named volume
docker run -d -v mydata:/app/data myapp
# Read-only volume
docker run -d -v myconfig:/etc/config:ro myapp
# Multiple volumes
docker run -d \
-v mydata:/app/data \
-v myconfig:/etc/config:ro \
-v logs:/var/log \
myapp
# Anonymous volume (Docker creates a random name)
docker run -d -v /app/data myapp
# Volume name: a1b2c3d4e5f6...
Listing and Inspecting
# List all volumes
docker volume ls
# DRIVER VOLUME NAME
# local mydata
# local pgdata
# local a1b2c3d4e5f6...
# Inspect volume details
docker volume inspect mydata
# List volumes with size
docker system df -v
Removing Volumes
# Remove a specific volume (must not be in use)
docker volume rm mydata
# Remove all unused volumes
docker volume prune
# Force remove (even if in use - DANGEROUS)
docker volume rm -f mydata
Backup and Restore
# Backup: Run container with volume and host mount
docker run --rm \
-v pgdata:/source:ro \
-v $(pwd):/backup \
alpine tar czf /backup/pgdata-backup.tar.gz -C /source .
# Restore: Create volume and extract backup
docker volume create pgdata-restored
docker run --rm \
-v pgdata-restored:/target \
-v $(pwd):/backup \
alpine tar xzf /backup/pgdata-backup.tar.gz -C /target
Copy Data Between Volumes
# Using a temporary container
docker run --rm \
-v source-vol:/source:ro \
-v target-vol:/target \
alpine cp -a /source/. /target/
Volume Drivers and Backends
Volume Drivers and Backends
Local Driver (Default)
The default local driver stores volumes on the Docker host's filesystem:
# Basic local volume
docker volume create --driver local mydata
# Local volume with NFS mount
docker volume create --driver local \
--opt type=nfs \
--opt o=addr=192.168.1.10,rw \
--opt device=:/exports/data \
nfs-volume
Cloud Volume Drivers
AWS EBS:
# Install plugin
docker plugin install --grant-all-permissions rexray/ebs
# Create EBS-backed volume
docker volume create --driver rexray/ebs \
--opt size=100 \
--opt volumetype=gp3 \
ebs-volume
# Use with container
docker run -d -v ebs-volume:/data myapp
Azure:
docker plugin install --grant-all-permissions azure/azurefile
# Create Azure File volume
docker volume create --driver azure/azurefile \
--opt filesharename=myshare \
--opt storageaccount=mystorageaccount \
azure-volume
NFS:
docker volume create --driver local \
--opt type=nfs \
--opt o=addr=192.168.1.10,rw \
--opt device=:/exports/data \
nfs-data
Volume Labels
# Create with labels
docker volume create --label env=production --label team=backend mydata
# Filter volumes by label
docker volume ls --filter label=env=production
Volume Best Practices
- Use named volumes for databases and persistent data
- Use read-only mounts for configuration files
- Always back up critical volumes before Docker upgrades
- Use volume drivers for network/cloud storage in production
- Never store sensitive data in volumes without encryption
- Use
:zor:Zsuffix on SELinux systems to fix permission issues