Skip to content

🐳 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 -v or --mount in docker run

  • The image does not declare a VOLUME instruction in its Dockerfile

  • You are not using a docker-compose.yml file 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

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:

  1. Start:
docker compose up
  1. Insert some data from your app

  2. Destroy containers:

docker compose down
  1. 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.