🐳 Docker Volumes — The Complete Guide (With Hands-On Labs)¶
Container filesystems are ephemeral — everything inside a container disappears when it stops or is deleted.
But real applications need persistent data:
-
PostgreSQL & MySQL databases
-
MongoDB collections
-
Redis persistence (AOF/RDB)
-
File uploads
-
Logs
-
Cache directories
This is why Docker Volumes exist.
This guide covers all Docker volume types, common use cases, backups, and production best practices — with practical labs you can run immediately.
- physical areas of disk space shared between the host and a container, or even between containers. In other words, a volume is a shared directory in the host, visible from some or all containers
🔥 Why Volumes Matter¶
Docker containers follow the principle:
"Containers are immutable — data is not."
If your PostgreSQL database stored data inside the container’s filesystem and the container restarted, you’d lose everything.
Volumes ensure:
-
Data persists across restarts
-
Data lives outside the container
-
Data survives image rebuilds
-
Multiple containers can share data
1️⃣ Types of Docker Volumes¶
Docker provides three ways to persist and manage data:
-
docker volume ls=> Lists all named volumes on your Docker host. -
Bind Mounts
-
Named Volumes
-
Anonymous Volumes
Let’s understand each.¶
2️⃣ Bind Mounts — Host Folder ↔ Container Folder¶
Bind mounts connect a real host directory into a container.
docker run -v /host/path:/container/path image
Or in compose:
volumes:
- ./uploads:/app/uploads
| ✔ Pros | ❌ Cons |
|---|---|
| Live reload (perfect for development) | OS‑dependent (Linux/Mac/Windows differences) |
| Easy to inspect files on host | Permission issues may occur |
| Complete control | Not ideal for production |
| Not portable between machines |
🧪 Hands-on Lab (Bind Mount)¶
Run nginx serving your local folder:
mkdir site
echo "Hello from host" > site/index.html
docker run -d -p 8080:80 \
-v $(pwd)/site:/usr/share/nginx/html \
nginx
Visit:
http://localhost:8080
Edit the file on your host → browser updates instantly.
Inspect Volume Mounts of a Container¶
docker inspect -f "{{ json .Mounts }}" 7b80fde78781(container ID)
#OUTPUT
[{ "Type": "volume", "Name": "data_volume", "Source": "/var/lib/docker/volumes/data_volume/_data", "Destination": "/var/lib/mysql", "Driver": "local", ... }]
⭐ Above command can give empty[] that is completely normal for a container to have no volumes at all.¶
✔ When a Container Has Zero Volumes¶
A container will have no volumes attached if:
-
You did not specify
-vor--mountindocker run -
The image does not declare a
VOLUMEinstruction in its Dockerfile -
You are not using a
docker-compose.ymlfile with volumes
In this case, the container uses its internal filesystem, which:¶
-
Lives inside Docker’s writable layer
-
Is deleted when the container is removed
-
Does not appear under
.Mounts
3️⃣ Named Volumes — Best for Databases (Postgres, MySQL, Redis, MongoDB)¶
Named volumes are managed by Docker internally.
Unlike bind mounts, they do not depend on host file paths.
Create:¶
docker volume create pgdata
Use:¶
docker run -d \
-v pgdata:/var/lib/postgresql/data \
postgres
✔ Pros¶
-
Fully managed by Docker
-
Cross-platform
-
Ideal for databases
-
Safe, stable, portable
-
Can be backed up easily
❌ Cons¶
-
Not visible in your project folder
-
Accessing data requires Docker commands
🧪 Hands-on Lab (Postgres + Named Volume)¶
Run PostgreSQL with a named volume:
docker volume create pg_data
docker run -d --name db \
-e POSTGRES_PASSWORD=pass \
-v pg_data:/var/lib/postgresql/data \
postgres
Stop the container:
docker stop db
docker rm db
Re-run:
docker run -d --name db \
-e POSTGRES_PASSWORD=pass \
-v pg_data:/var/lib/postgresql/data \
postgres
✔ Your data is still there.
when docker creates named volume automatically¶
docker run -v data_volume:/var/lib/mysql mysql
# Automatic creation: If data_volume does not exist, Docker will automatically create it in the host system, typically at: /var/lib/docker/volumes/data_volume/_data
4️⃣ Anonymous Volumes — Automatically Created (Avoid for Production)¶
Docker automatically creates a volume if you specify:
docker run -v /app/data image
It generates a random name like:
2c75af34e93b9d441384b2a95c22ac99e82355cc57ae64b40
✔ Good for:¶
-
Temporary containers
-
Cache layers
-
Build pipelines
❌ Bad for:¶
-
Databases
-
Production environments
-
Anything requiring tracking
🚀 Share a volume between containers¶
- Use a named Docker volume (recommended)
docker run --name myapp_web --volumes-from myapp_data -d nginx
Explanation¶
-
myapp_data→ Existing container that has the volume with your persistent data (e.g., website files). -
myapp_web→ New container that will use the same volume as myapp_data. -
volumes-from myapp_data→ Mounts all volumes from myapp_data into myapp_web. -
d nginx→ Runs the container in detached mode with the Nginx image.
Use Case:¶
You can update, replace, or scale your web container (myapp_web) without losing the data stored in myapp_data.
Verify that volumes are shared¶
docker exec c1 sh -c "echo hi > /app/data/test.txt"
docker exec c2 cat /app/data/test.txt
# OUTPUT
hi
¶
docker exec c1 sh -c "echo hi > /app/data/test.txt"
docker exec c2 cat /app/data/test.txt
# OUTPUT
hi
5️⃣ Where Does Docker Store Named Volumes?¶
On Linux:
/var/lib/docker/volumes/<name>/_data
On Mac/Windows (Docker Desktop):
-
Stored inside a VM
-
Access using:
docker run -it --rm -v <vol>:/data alpine sh
6️⃣ Volume Backups (Must-Know for Interviews)¶
🔹 Backup a volume:¶
docker run --rm \
-v pg_data:/data \
-v $(pwd):/backup \
busybox tar cvf /backup/pg-backup.tar /data
🔹 Restore:¶
docker run --rm \
-v pg_data:/data \
-v $(pwd):/backup \
busybox tar xvf /backup/pg-backup.tar -C /
This is frequently asked in DevOps interviews.
7️⃣ Volume Drivers (Advanced)¶
Use external volume drivers for:
-
AWS EBS
-
Azure Disk
-
Google Cloud Disk
-
NFS
-
Ceph
Example:
docker volume create \
--driver rexray/ebs \
--name my-ebs-volume
This allows persistent storage across cloud servers.
8️⃣ File & Directory Permission Issues (Common Problem)¶
Linux permissions often cause container errors like:
Permission denied
Fix by passing user ID:¶
docker run -u $(id -u):$(id -g) ...
Or adjust ownership:
chown -R 1000:1000 mydata/
9️⃣ Best Practices for Docker Volumes (Production-Grade)¶
✔ 1. Use named volumes for databases¶
They are stable, portable, easy to back up.
✔ 2. Use bind mounts only for development¶
Host files change quickly → hot reload.
✔ 3. Never store DB data inside image¶
Images are immutable; data must be external.
✔ 4. One volume per major service¶
Avoid mixing logs, DB, uploads into one volume.
✔ 5. Manage volumes via Compose¶
Define them cleanly:
volumes:
db_data:
uploads:
🧪 Hands-On Labs (Complete Mini Project)¶
Lab A: Full Stack App With DB Persistence¶
docker-compose.yml¶
services:
app:
image: node:18
working_dir: /app
volumes:
- ./src:/app
command: ["node", "server.js"]
ports:
- "3000:3000"
depends_on:
- db
db:
image: postgres
environment:
POSTGRES_PASSWORD: pass
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
Steps:¶
- Start:
docker compose up
-
Insert some data from your app
-
Destroy containers:
docker compose down
- Start again:
docker compose up
✔ Data persists.
Lab B: Shared Volume Between Multiple Containers¶
docker run -d --name writer \
-v shared:/data \
alpine sh -c "echo hello > /data/file.txt"
docker run -it --name reader \
-v shared:/data \
alpine cat /data/file.txt
✔ One writes, one reads.
🔥 Interview Questions & Answers¶
❓1. Named Volume vs Bind Mount?¶
| Feature | Bind Mount | Named Volume |
|---|---|---|
| Location | Host filesystem | Docker‑managed |
| Portability | Low | High |
| Best Use | Dev | Databases |
| Risk | Permissions issues | Very stable |
❓2. Why shouldn’t we store DB data inside container?¶
Because:
-
Data will be lost on container removal
-
Image rebuild removes data
-
No persistence
-
Not scalable
❓3. How do volumes work internally?¶
They map host paths to container paths using:
-
Mount namespaces
-
Virtual filesystems
-
OverlayFS
❓4. How to back up named volumes?¶
Using busybox or alpine + tar (shown above).
❓5. Can two containers share a volume?¶
YES.
That’s how:
-
NFS-like behavior works
-
WordPress + PHP-FPM share files
-
Cache & job workers share temp storage
🏁 Final Summary¶
You now understand:
-
Bind mounts (for dev)
-
Named volumes (for production databases)
-
Backup + restore strategy
-
Volume drivers
-
Real labs and use cases
-
Interview topics
Volumes are the backbone of persistent storage in Docker and a required skill for DevOps, backend engineering, and microservices.