Now let's learn about one of the most important topics in Docker - how to manage data in containers.
Part 1: The Container Data Problem
Understanding Container Filesystem
Important Concept: Containers are EPHEMERAL (temporary)
What does this mean?
When you create a container:
├── It has its own filesystem
├── You can create/modify files inside
├── Everything works normally
When you delete the container:
├── ALL data inside is lost! ✗
├── Files gone forever
└── No way to recover
Demonstrating the Problem
Let's see this in action!
Step 1: Run Ubuntu container and create a file
docker run -it --name test-container ubuntu bash
Inside the container:
# You're now inside Ubuntu container
# Create a file
echo "Important data!" > /data.txt
# Verify it exists
cat /data.txt
# Output: Important data!
# Exit container
exit
Step 2: Start the same container again
docker start test-container
docker exec -it test-container bash
Inside container:
# Check if file still exists
cat /data.txt
# Output: Important data!
# File is still there! ✓
exit
Step 3: Remove and create new container
# Remove the container
docker rm test-container
# Create a new container (same image)
docker run -it --name test-container2 ubuntu bash
Inside new container:
# Try to find the file
cat /data.txt
# Error: No such file or directory ✗
# File is GONE! ✗
What happened?
Container 1:
├── Created data.txt
├── Data stored in container's writable layer
└── Removed → Data lost forever! ✗
Container 2:
├── Fresh container from same image
├── No data from Container 1
└── Starting from scratch
Problem: Data is tied to container lifecycle!
Real-World Problem Scenarios
Scenario 1: Database Container
Run MySQL container:
├── Create database
├── Add tables
├── Insert 1000 customer records
Container crashes:
├── Restart container → Data still there ✓
Accidentally delete container:
├── All data GONE! ✗
├── 1000 customer records lost!
└── Disaster! ✗
Scenario 2: Web Application
Upload feature:
├── Users upload photos
├── Photos saved in /uploads/ inside container
Update application (new container):
├── Deploy new version
├── Remove old container
├── All uploaded photos GONE! ✗
└── Users angry! ✗
Scenario 3: Log Files
Application writes logs:
├── Debug logs in /var/log/app/
├── Error logs accumulating
Container deleted:
├── All logs lost ✗
├── Can't debug past issues ✗
└── No audit trail ✗
The Solution: Docker Volumes
Volumes = Persistent storage outside the container
Think of it as:
Container = Temporary hotel room
├── You stay there temporarily
├── When you check out, room is cleaned
└── Your stuff is gone
Volume = Your storage unit
├── Permanent storage space
├── Exists outside the hotel
├── Your stuff stays even after checkout
└── Can access from any room (container)
Visual:
WITHOUT Volumes:
┌──────────────────┐
│ Container │
│ │
│ /data/ │ ← Data inside
│ └── files │
└──────────────────┘
↓ Delete
Data lost! ✗
WITH Volumes:
┌──────────────────┐ ┌──────────────┐
│ Container │ │ Volume │
│ │────→│ │
│ /data/ (mount) │ │ Real data │
│ │ │ stored here │
└──────────────────┘ └──────────────┘
↓ Delete ↓
Container gone Data safe! ✓
Part 2: What are Docker Volumes?
Simple Definition
Volume = A storage space managed by Docker that exists outside containers
Key Characteristics:
Volumes are:
├── Persistent (survive container deletion)
├── Managed by Docker
├── Can be shared between containers
├── Independent of container lifecycle
├── Stored on host machine
└── Easy to backup
How Volumes Work
Conceptual Model:
Host Machine (Your Computer):
├── Docker manages a special directory
├── /var/lib/docker/volumes/ (Linux)
├── This is where volume data is stored
Volume:
├── Named storage space
├── Like a hard drive managed by Docker
Container:
├── Mounts (connects to) the volume
├── Sees volume as a directory
└── Reads/writes to volume = permanent storage
Visual:
Your Computer Filesystem:
/var/lib/docker/volumes/
├── my-volume/
│ └── _data/
│ ├── file1.txt
│ └── file2.txt
└── db-volume/
└── _data/
└── database.db
Container:
/app/data/ ──(mounted)──→ my-volume
↓
Actual storage location
Part 3: Creating and Using Volumes
Creating a Volume
Syntax:
docker volume create VOLUME_NAME
Example:
docker volume create my-data
Output:
my-data
That's it! Volume created! ✓
Listing Volumes
docker volume ls
Output:
DRIVER VOLUME NAME
local my-data
Inspecting a Volume
docker volume inspect my-data
Output:
[
{
"CreatedAt": "2026-02-24T10:30:00Z",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/my-data/_data",
"Name": "my-data",
"Options": {},
"Scope": "local"
}
]
Important field:
Mountpoint: "/var/lib/docker/volumes/my-data/_data"
↑
Where data is actually stored on your computer
Using a Volume with Container
Mount volume when running container:
Syntax:
docker run -v VOLUME_NAME:/path/in/container IMAGE
Example:
docker run -it -v my-data:/data ubuntu bash
What this does:
-v my-data:/data
↑ ↑
│ └── Path inside container
└── Volume name
Container sees /data/ directory
/data/ is actually stored in my-data volume
Data persists even after container is deleted!
Practical Example: Persistent Data
Let's see volumes in action!
Step 1: Create a volume
docker volume create persistent-data
Step 2: Run container with volume
docker run -it --name container1 -v persistent-data:/data ubuntu bash
Inside container:
# Create some files
echo "This data will persist!" > /data/important.txt
echo "User database" > /data/users.db
echo "Configuration" > /data/config.json
# List files
ls /data/
# Output: important.txt users.db config.json
# Exit
exit
Step 3: Delete the container
docker rm container1
Step 4: Create NEW container with SAME volume
docker run -it --name container2 -v persistent-data:/data ubuntu bash
Inside new container:
# Check if data exists
ls /data/
# Output: important.txt users.db config.json
cat /data/important.txt
# Output: This data will persist!
# Data is still there! ✓
# Even though we deleted container1!
🎉 Volume preserved the data!
Multiple Containers Sharing a Volume
Volumes can be shared between containers!
Terminal 1:
docker run -it --name writer -v shared-data:/data ubuntu bash
Inside writer container:
# Write data
echo "Message from writer" > /data/message.txt
# Keep container running
sleep infinity
Terminal 2 (new terminal):
docker run -it --name reader -v shared-data:/data ubuntu bash
Inside reader container:
# Read data written by writer
cat /data/message.txt
# Output: Message from writer
# Data shared between containers! ✓
Use case:
Example: Microservices sharing data
Container 1 (Producer):
└── Writes log files to /logs
Container 2 (Analyzer):
└── Reads log files from /logs
Both mount same volume:
└── Data flows between them! ✓
Part 4: Bind Mounts
What are Bind Mounts?
Bind Mount = Mount a directory from YOUR computer into a container
Difference from Volumes:
Volume:
├── Managed by Docker
├── Stored in Docker's directory
└── docker volume create my-vol
Bind Mount:
├── You choose the directory
├── Any directory on your computer
└── Mount your own folder
Visual:
Volume (Managed by Docker):
Your Computer Container
Docker manages:
/var/lib/docker/volumes/
└── my-vol/_data/ ────→ /data/
└── files
Bind Mount (You manage):
Your Computer Container
Your directory:
C:\Users\You\project\
└── code/ ────→ /app/
└── files
Creating Bind Mounts
Syntax:
docker run -v /host/path:/container/path IMAGE
Windows example:
docker run -v C:\Users\YourName\myapp:/app ubuntu
Absolute path required!
Practical Example: Development Workflow
This is EXTREMELY useful for development!
Scenario: Developing a Python app
Step 1: Create project directory
mkdir C:\Users\YourName\python-app
cd C:\Users\YourName\python-app
Step 2: Create app.py
# app.py
print("Hello from Python!")
print("Version 1.0")
Step 3: Run with bind mount
docker run -it -v C:\Users\YourName\python-app:/app python:3.11 bash
Inside container:
cd /app
ls
# Output: app.py
python app.py
# Output:
# Hello from Python!
# Version 1.0
# Keep container running
sleep infinity
Step 4: Edit file on YOUR computer (not in container)
Open app.py in your editor and change it:
# app.py
print("Hello from Python!")
print("Version 2.0 - Updated!")
print("New feature added!")
Save the file
Step 5: Run again in container (same container still running)
# Still inside the container
python app.py
# Output:
# Hello from Python!
# Version 2.0 - Updated!
# New feature added!
# Changes reflected immediately! ✓
What happened?
File on your computer:
C:\Users\YourName\python-app\app.py
↓
(bind mount)
↓
File in container:
/app/app.py
They're the SAME file!
Edit on computer → Changes in container immediately! ✓
Bind Mount Benefits for Development
Traditional development:
Without bind mount:
1. Edit code on computer
2. Copy code into container (slow)
3. Test
4. Find bug
5. Exit container
6. Edit code again
7. Copy into container again (slow)
8. Repeat... ✗
With bind mount:
With bind mount:
1. Edit code on computer
2. Changes instantly in container ✓
3. Test immediately
4. Edit again
5. Test immediately
6. Fast iteration! ✓
Modern Bind Mount Syntax
Old syntax:
docker run -v C:\path:/container/path image
New syntax (recommended):
docker run --mount type=bind,source=C:\path,target=/container/path image
Example:
docker run --mount type=bind,source=C:\Users\YourName\myapp,target=/app python:3.11
Both work, but --mount is more explicit and clear.
Part 5: Volume vs Bind Mount - When to Use What?
Comparison
┌─────────────────────────────────────────────────────┐
│ VOLUMES vs BIND MOUNTS │
├─────────────────────────────────────────────────────┤
│ │
│ VOLUMES: │
│ ✓ Managed by Docker │
│ ✓ Better for production │
│ ✓ Works on all platforms │
│ ✓ Easy to backup │
│ ✓ Can be shared easily │
│ ✗ Need docker volume commands to manage │
│ │
│ BIND MOUNTS: │
│ ✓ Direct access to files │
│ ✓ Great for development │
│ ✓ Easy to edit files │
│ ✓ No docker commands needed │
│ ✗ Path must exist on host │
│ ✗ Platform-specific paths │
│ │
└─────────────────────────────────────────────────────┘
When to Use Volumes
Use volumes for:
✓ Database data
└── MySQL, PostgreSQL, MongoDB
✓ Production data
└── Uploaded files, generated reports
✓ Data that must persist
└── User data, configurations
✓ Shared data between containers
└── Microservices communication
✓ Backups
└── Easy to backup entire volume
Example: Database
docker run -d \
--name mysql-db \
-v mysql-data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=secret \
mysql:8.0
When to Use Bind Mounts
Use bind mounts for:
✓ Development
└── Edit code on computer, test in container
✓ Configuration files
└── nginx.conf, app config
✓ Source code during development
└── Live reload
✓ When you need direct file access
└── Easy to edit/view files
Example: Development
docker run -d \
-v C:\Users\You\myapp:/app \
-p 5000:5000 \
python:3.11 \
python /app/app.py
Part 6: Real-World Examples
Example 1: MySQL Database with Volume
Run MySQL with persistent data:
# Create volume for database
docker volume create mysql-data
# Run MySQL container
docker run -d \
--name mysql-db \
-v mysql-data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=mypassword \
-e MYSQL_DATABASE=myapp \
-p 3306:3306 \
mysql:8.0
What happens:
Container created:
├── MySQL running
├── Creates database files
└── Stored in mysql-data volume
Stop/Remove container:
├── Container gone
└── Data safe in volume ✓
Start new container with same volume:
├── All databases restored ✓
└── No data loss ✓
Test it:
# Connect to MySQL
docker exec -it mysql-db mysql -uroot -pmypassword
# Inside MySQL:
CREATE TABLE users (id INT, name VARCHAR(50));
INSERT INTO users VALUES (1, 'Alice');
SELECT * FROM users;
# Data created ✓
exit
# Remove container
docker stop mysql-db
docker rm mysql-db
# Create new container with same volume
docker run -d \
--name mysql-db-new \
-v mysql-data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=mypassword \
mysql:8.0
# Wait 10 seconds for MySQL to start
# Connect again
docker exec -it mysql-db-new mysql -uroot -pmypassword myapp
# Check data
SELECT * FROM users;
# Output: 1 | Alice
# Data persisted! ✓
Example 2: Web App Development with Bind Mount
Create a simple web app:
Directory structure:
my-website/
├── index.html
├── style.css
└── app.js
index.html:
<!DOCTYPE html>
<html>
<head>
<title>My App</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>Hello Docker!</h1>
<p id="message">Loading...</p>
<script src="app.js"></script>
</body>
</html>
style.css:
body {
font-family: Arial;
background-color: #f0f0f0;
padding: 20px;
}
app.js:
document.getElementById('message').textContent = 'Version 1.0';
Run with bind mount:
docker run -d \
--name web-dev \
-v C:\Users\YourName\my-website:/usr/share/nginx/html \
-p 8080:80 \
nginx:alpine
Access: http://localhost:8080
Now edit files on your computer:
Change app.js:
document.getElementById('message').textContent = 'Version 2.0 - UPDATED!';
Refresh browser → Changes appear immediately! ✓
No need to rebuild or restart container!
Example 3: Sharing Data Between Containers
Scenario: Log producer and analyzer
Create shared volume:
docker volume create shared-logs
Container 1: Producer (generates logs)
docker run -d \
--name log-producer \
-v shared-logs:/logs \
ubuntu \
bash -c "while true; do echo \"Log entry: $(date)\" >> /logs/app.log; sleep 5; done"
Container 2: Analyzer (reads logs)
docker run -it \
--name log-analyzer \
-v shared-logs:/logs \
ubuntu \
bash
Inside analyzer:
# Watch logs in real-time
tail -f /logs/app.log
# Output:
# Log entry: Mon Feb 24 10:30:00 UTC 2026
# Log entry: Mon Feb 24 10:30:05 UTC 2026
# Log entry: Mon Feb 24 10:30:10 UTC 2026
# ... keeps updating
# Both containers accessing same volume! ✓
Part 7: Volume Commands Reference
Complete Volume Commands
# Create volume
docker volume create VOLUME_NAME
# List volumes
docker volume ls
# Inspect volume (see details)
docker volume inspect VOLUME_NAME
# Remove volume
docker volume rm VOLUME_NAME
# Remove all unused volumes
docker volume prune
# Remove volume with force
docker volume rm -f VOLUME_NAME
Using Volumes with Containers
# Run with named volume
docker run -v VOLUME_NAME:/path IMAGE
# Run with bind mount (absolute path)
docker run -v /host/path:/container/path IMAGE
# Run with bind mount (current directory)
docker run -v ${PWD}:/app IMAGE
# Multiple volumes
docker run -v vol1:/data1 -v vol2:/data2 IMAGE
# Read-only volume
docker run -v VOLUME_NAME:/path:ro IMAGE
# :ro = read-only
Modern Mount Syntax
# Volume mount
docker run --mount type=volume,source=VOLUME_NAME,target=/path IMAGE
# Bind mount
docker run --mount type=bind,source=/host/path,target=/path IMAGE
# Read-only mount
docker run --mount type=volume,source=VOL,target=/path,readonly IMAGE
Part 8: Anonymous Volumes
What are Anonymous Volumes?
Anonymous Volume = Volume without a name
Created automatically by Docker when you don't specify name:
docker run -v /data ubuntu
# ↑
# No name = anonymous volume
Docker generates random name:
VOLUME NAME
a1b2c3d4e5f6...
When Anonymous Volumes are Used
Example: Some images create anonymous volumes by default
# In Dockerfile
VOLUME /data
When container runs, creates anonymous volume automatically.
Problem with Anonymous Volumes
docker run image1
# Creates anonymous volume: abc123
docker run image1
# Creates ANOTHER anonymous volume: def456
docker run image1
# Creates ANOTHER anonymous volume: ghi789
Result:
├── 3 containers
├── 3 anonymous volumes
└── Hard to manage! ✗
Better: Use named volumes!
docker run -v my-data:/data image
# Same named volume reused ✓
Part 9: Backing Up and Restoring Volumes
Backup a Volume
Method: Use a temporary container to tar the volume
# Backup volume to tar file
docker run --rm -v VOLUME_NAME:/data -v ${PWD}:/backup ubuntu tar czf /backup/backup.tar.gz /data
Explanation:
--rm = Remove container after done
-v VOLUME_NAME:/data = Mount volume to backup
-v ${PWD}:/backup = Mount current directory
ubuntu = Use Ubuntu image
tar czf /backup/backup.tar.gz /data = Compress /data to backup file
Example:
# Backup mysql-data volume
docker run --rm \
-v mysql-data:/data \
-v C:\Users\You\backups:/backup \
ubuntu \
tar czf /backup/mysql-backup.tar.gz /data
Restore a Volume
# Create new volume
docker volume create restored-data
# Restore from backup
docker run --rm \
-v restored-data:/data \
-v ${PWD}:/backup \
ubuntu \
bash -c "cd /data && tar xzf /backup/backup.tar.gz --strip 1"
Part 10: Cleaning Up Volumes
Remove Single Volume
# Must stop/remove containers using it first
docker volume rm VOLUME_NAME
If volume is in use:
Error: volume is in use
Solution:
1. docker ps -a (find containers using volume)
2. docker rm CONTAINER (remove those containers)
3. docker volume rm VOLUME_NAME (now works)
Remove All Unused Volumes
docker volume prune
Output:
WARNING! This will remove all local volumes not used by at least one container.
Are you sure you want to continue? [y/N] y
Deleted Volumes:
volume1
volume2
anonymous-volume-abc123
Total reclaimed space: 2.5GB
Be careful! This removes data permanently!
Practice Exercises
Exercise 1: Persistent Counter
Create a container that counts:
# Create volume
docker volume create counter-data
# Run container
docker run -it -v counter-data:/data ubuntu bash
Inside container:
# Create counter file
echo "0" > /data/count.txt
# Increment counter
COUNT=$(cat /data/count.txt)
COUNT=$((COUNT + 1))
echo $COUNT > /data/count.txt
echo "Count: $COUNT"
exit
Run again (multiple times):
docker run -it -v counter-data:/data ubuntu bash
Inside container:
# Increment and show
COUNT=$(cat /data/count.txt)
COUNT=$((COUNT + 1))
echo $COUNT > /data/count.txt
echo "Count: $COUNT"
Each time, count increases! Data persists! ✓
Exercise 2: Development Environment
Setup:
# Create project directory
mkdir my-python-project
cd my-python-project
# Create app.py
echo print("Hello!") > app.py
# Run with bind mount
docker run -it -v ${PWD}:/app python:3.11 bash
Inside container:
cd /app
python app.py
Now edit app.py on your computer, run again in container → See changes!
Summary
What We Learned:
✅ Container data is temporary by default
✅ Volumes provide persistent storage
✅ Three types of mounts:
├── Named volumes (managed by Docker)
├── Anonymous volumes (random names)
└── Bind mounts (your directories)
✅ When to use volumes vs bind mounts
✅ Creating and managing volumes
✅ Sharing data between containers
✅ Backing up and restoring
✅ Real-world examples
Key Takeaways:
Volumes:
├── Use for production data
├── Database storage
├── Persistent application data
└── Easy backups
Bind Mounts:
├── Use for development
├── Source code
├── Configuration files
└── Direct file access
No comments:
Post a Comment