Docker Volumes
Volumes are a way to persist data outside the container lifecycle. The data remains even after the container is deleted.
Storage Types
1. Volumes
# Create a volume
docker volume create myapp-db-data
# List volumes
docker volume ls
# Inspect a volume
docker volume inspect myapp-db-data
# Use a volume
docker run -d \
--name db \
-v myapp-db-data:/var/lib/postgresql/data \
postgres:15
# Delete a volume
docker volume rm myapp-db-data
2. Bind Mounts
# Mount a host directory
docker run -d \
--name app \
-v /host/path:/container/path \
myapp:latest
# Mount a specific file
docker run -d \
--name app \
-v /host/config.json:/app/config.json:ro \
myapp:latest
3. Tmpfs Mounts
# Temporary mount in memory
docker run -d \
--name app \
--tmpfs /app/temp:rw,size=100m \
myapp:latest
Volume Commands
# List all volumes
docker volume ls
# View volume details
docker volume inspect volume_name
# Delete unused volumes
docker volume prune
# Back up a volume
docker run --rm \
-v myapp-db-data:/source:ro \
-v $(pwd):/backup \
alpine tar czf /backup/backup.tar.gz -C /source .
# Restore a volume
docker run --rm \
-v myapp-db-data:/target \
-v $(pwd):/backup \
alpine tar xzf /backup/backup.tar.gz -C /target
Use Case: Application Database
# PostgreSQL with a persistent volume
docker run -d \
--name myapp-db \
-e POSTGRES_DB=myapp \
-e POSTGRES_USER=admin \
-e POSTGRES_PASSWORD=secret123 \
-v myapp-db-data:/var/lib/postgresql/data \
-v ./init-scripts:/docker-entrypoint-initdb.d \
-p 5432:5432 \
postgres:15
# Back up the database
docker exec myapp-db pg_dump -U admin myapp > backup.sql
# Restore the database
cat backup.sql | docker exec -i myapp-db psql -U admin myapp
Use Case: Development
# Run with a bind mount for development
docker run -d \
--name dev-app \
-v $(pwd):/app \
-v /app/node_modules \
-p 3000:3000 \
node:18-alpine \
npm run dev
Docker Compose with Volumes
version: '3.8'
services:
db:
image: postgres:15
environment:
POSTGRES_DB: myapp
POSTGRES_USER: admin
POSTGRES_PASSWORD: secret123
volumes:
- db-data:/var/lib/postgresql/data
- ./init-scripts:/docker-entrypoint-initdb.d
ports:
- "5432:5432"
api:
build: ./backend
environment:
DB_HOST: db
DB_PORT: 5432
DB_NAME: myapp
DB_USER: admin
DB_PASSWORD: secret123
volumes:
- ./backend/src:/app/src
ports:
- "3000:3000"
depends_on:
- db
volumes:
db-data:
Backup and Restore
Backup
# Back up PostgreSQL
docker exec myapp-db pg_dump -U admin myapp > backup_$(date +%Y%m%d).sql
# Back up Redis
docker exec myapp-redis redis-cli BGSAVE
docker cp myapp-redis:/data/dump.rdb ./backup_redis.rdb
Restore
# Restore PostgreSQL
cat backup.sql | docker exec -i myapp-db psql -U admin myapp
# Restore Redis
docker cp ./backup_redis.rdb myapp-redis:/data/dump.rdb
docker restart myapp-redis
Everyday Use Case
Case: A developer needs to back up data before an update.
# Back up all volumes
docker run --rm \
-v myapp-db-data:/source:ro \
-v $(pwd)/backups:/backup \
alpine tar czf /backup/db_$(date +%Y%m%d).tar.gz -C /source .
# Update the application
docker-compose pull
# Restart with the data still present
docker-compose up -d
Best Practices
- Use named volumes: Easier to manage
- Back up regularly: Schedule automatic backups
- Delete unused volumes:
docker volume prune - Use bind mounts for development: For hot reload
- Don't use bind mounts for important data: Use named volumes
Troubleshooting
Volume not mounted
# Check permissions
ls -la /host/path
# Make sure the path is correct
docker inspect container_name | grep Mounts
Data lost after restart
# Make sure you are using a named volume
docker volume ls
# Check the mount point
docker inspect container_name | grep -A 5 "Mounts"
Conclusion
Volumes are essential for persisting data. For applications, use named volumes for databases and bind mounts for development. Back up regularly to prevent data loss.