This tutorial demonstrates how to use Docker volumes to persist data across container restarts and rebuilds using Nginx as a web server.
Lab2/
├── Dockerfile
├── docker-compose.yml
├── html/
│ └── index.html
└── README.md
- Docker installed on your machine
- Basic understanding of Docker concepts
docker build -t nginx-volume-demo .docker volume create web-contentdocker run -d --name nginx-volume-container \
-p 8080:80 \
-v $(pwd)/html:/usr/share/nginx/html \
nginx-volume-demodocker run -d --name nginx-volume-container \
-p 8080:80 \
-v web-content:/usr/share/nginx/html \
nginx-volume-demoOpen your browser and navigate to http://localhost:8080
- Modify the html/index.html file
- Refresh your browser to see changes immediately
- Stop and remove the container:
docker stop nginx-volume-container docker rm nginx-volume-container
- Start a new container with the same volume:
docker run -d --name nginx-volume-container-new \ -p 8080:80 \ -v $(pwd)/html:/usr/share/nginx/html \ nginx-volume-demo - Verify your changes are still there at http://localhost:8080
docker-compose up -dOpen your browser and navigate to http://localhost:8080
- Modify the html/index.html file
- Refresh your browser to see changes immediately
- Stop and remove containers:
docker-compose down
- Start services again:
docker-compose up -d
- Verify your changes are still there at http://localhost:8080
Docker volumes are the preferred way to persist data generated by and used by Docker containers. Unlike bind mounts, volumes are completely managed by Docker.
┌──────────────────────────────────────────────────────────┐
│ │
│ Docker Volume Architecture │
│ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ Container A │ │ Container B │ │
│ │ │ │ │ │
│ │ ┌─────────┐ │ │ ┌─────────┐ │ │
│ │ │Mount │ │ │ │Mount │ │ │
│ │ │Point │ │ │ │Point │ │ │
│ │ └────┬────┘ │ │ └────┬────┘ │ │
│ └──────┼──────┘ └──────┼──────┘ │
│ │ │ │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────────────────────────────────┐ │
│ │ │ │
│ │ Docker Volume │ │
│ │ │ │
│ └──────────────────────────────────────┘ │
│ │ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────┐ │
│ │ │ │
│ │ Docker's Storage Location │ │
│ │ (e.g., /var/lib/docker/volumes) │ │
│ │ │ │
│ └──────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────┘
- Bind Mounts: We're mapping a directory from the host (./html) to a directory in the container (/usr/share/nginx/html).
┌──────────────────────────────────────────────────────────┐
│ Bind Mount Workflow │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Host System │ │ Container │ │
│ │ │ │ │ │
│ │ ┌─────────────┐ │ │ ┌─────────────┐ │ │
│ │ │ │ │ mapped │ │ │ │ │
│ │ │ ./html │◄├───────────┤►│/usr/share/ │ │ │
│ │ │ directory │ │ directly │ │nginx/html │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ └─────────────┘ │ │ └─────────────┘ │ │
│ │ │ │ │ │
│ └─────────────────┘ └─────────────────┘ │
│ │
└──────────────────────────────────────────────────────────┘
- Named Volumes: Shown in the Docker CLI alternative approach.
┌──────────────────────────────────────────────────────────┐
│ Named Volume Workflow │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Docker Volume │ │ Container │ │
│ │ │ │ │ │
│ │ ┌─────────────┐ │ │ ┌─────────────┐ │ │
│ │ │ │ │ mounted │ │ │ │ │
│ │ │web-content │◄├───────────┤►│/usr/share/ │ │ │
│ │ │ volume │ │ to │ │nginx/html │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ └─────────────┘ │ │ └─────────────┘ │ │
│ │ │ │ │ │
│ └─────────────────┘ └─────────────────┘ │
│ │ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Docker Managed │ │
│ │ Storage Area │ │
│ └─────────────────┘ │
│ │
└──────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────┐
│ Volume Data Persistence │
│ │
│ ┌────────────┐ Stop & ┌────────────────┐ │
│ │ Container 1│ Remove │ Container 2 │ │
│ │ │ │ │ │
│ │ │ ────────► │ │ │
│ │ │ then │ │ │
│ │ │ create │ │ │
│ └──────┬─────┘ └────────┬───────┘ │
│ │ │ │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────────────────────────────────────────┐ │
│ │ │ │
│ │ Same Volume │ │
│ │ (Data is preserved) │ │
│ │ │ │
│ └──────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────┘
- Data Persistence: Data persists independently of container lifecycle
- Host-Container Sharing: Easy sharing of data between host and container
- Performance: Improved performance (especially for databases or file-intensive applications)
- Multi-container Access: Can be shared across multiple containers
┌──────────────────────────────────────────────────────────┐
│ Volume Benefits │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Container A │ │ Container B │ │ Container C │ │
│ │ (Web Server)│ │ (Backup │ │ (Dev │ │
│ │ │ │ Process) │ │ Process) │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ │ │
│ │ Shared Volume │ │
│ │ │ │
│ └─────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────┘
┌───────────────────────────────────────────────────────────┐
│ Volume Type Comparison │
│ │
│ ┌───────────────────┐ ┌───────────────────┐ │
│ │ Bind Mount │ │ Named Volume │ │
│ ├───────────────────┤ ├───────────────────┤ │
│ │ • Host path based │ │ • Docker managed │ │
│ │ • Good for dev │ │ • Better for prod │ │
│ │ • Direct access │ │ • Portable │ │
│ │ from host │ │ • Easier to back │ │
│ │ • Follows host │ │ up and restore │ │
│ │ filesystem │ │ • Content isolated│ │
│ │ permissions │ │ from host │ │
│ └───────────────────┘ └───────────────────┘ │
│ │
└───────────────────────────────────────────────────────────┘
- Databases: MySQL, PostgreSQL, MongoDB
- Web Server Content: As demonstrated in this example
- Application Logs: Persistent logging across container restarts
- Configuration Files: Sharing configuration across container instances
┌────────────────────────────────────────────────────────────┐
│ Volume Lifecycle │
│ │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 1. Create │ │ 2. Use with │ │ 3. Persist │ │
│ │ Volume │───►│ Container │───►│ Data │ │
│ │ │ │ │ │ │ │
│ └─────────────┘ └─────────────┘ └──────┬──────┘ │
│ ▲ │ │
│ │ │ │
│ │ ▼ │
│ ┌─────────────┐ ┌────────────────┐ │
│ │ 5. Remove │◄───────────────────────┤ 4. Stop/Remove │ │
│ │ Volume │ │ Container │ │
│ │ (Optional) │ │ │ │
│ └─────────────┘ └────────────────┘ │
│ │
└────────────────────────────────────────────────────────────┘
# For Docker CLI approach
docker stop nginx-volume-container
docker rm nginx-volume-container
docker volume rm web-content
# For Docker Compose approach
docker-compose downdocker volume inspect web-contentOutput example:
[
{
"CreatedAt": "2025-03-30T16:42:15Z",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/web-content/_data",
"Name": "web-content",
"Options": {},
"Scope": "local"
}
]
docker volume lsdocker volume prune# Create a tarball backup of a volume
docker run --rm -v web-content:/source -v $(pwd):/backup alpine tar -czvf /backup/web-content-backup.tar.gz -C /source .# Restore from a backup tarball
docker run --rm -v web-content:/target -v $(pwd):/backup alpine sh -c "tar -xzvf /backup/web-content-backup.tar.gz -C /target"