🚀DAY28: Docker Volumes Guide (Day 28) 🗂️


Welcome to Day 28: Docker Volumes of your Phase 2: Containers & Automation learning journey! 🎉 This guide dives into Docker volumes, a critical tool for persisting data in ephemeral containers. With clear theory, hands-on tasks, and stylish formatting, you’ll master volumes and bind mounts, preparing you for your Flask + Nginx + MongoDB project. Let’s make data persistence fun and practical! 💾
📚 Theory: Understanding Docker Volumes
Docker containers are ephemeral—when they’re removed, their data vanishes unless stored persistently. Docker volumes solve this by providing a way to save data beyond a container’s lifecycle and share it between containers or the host.
Why Use Volumes? 🤔
Purpose: Ensure data (e.g., database files, logs) survives container deletion.
Use Cases:
Persisting MongoDB data for your project.
Sharing configuration files or logs.
Backing up or migrating data.
Benefits:
Persistence: Data outlives containers.
Portability: Share or move data easily.
Isolation: Separates app logic from storage.
Types of Volumes 🗄️
Type | Description | Best For | Pros | Cons |
Docker Volumes | Managed by Docker, stored in /var/lib/docker/volumes/ | Production (e.g., MongoDB /data/db ) | Portable, Docker-managed, optimized | Less visibility into storage location |
Bind Mounts | Maps a host directory/file to a container path | Development (e.g., Flask code) | Direct host access, easy edits | Less portable, manual permissions |
🛠️ Key Commands Explained
Here are the essential Docker volume commands, with detailed explanations to ensure you understand their purpose and usage. These commands are your toolkit for practicing volumes! 🔧
Command | Purpose | Example | Explanation |
docker volume create <name> | Creates a Docker-managed volume | docker volume create my-data | Initializes a volume in Docker’s storage (e.g., /var/lib/docker/volumes/my-data/_data ). Use for persistent storage like MongoDB data. |
docker volume ls | Lists all volumes | docker volume ls | Shows all Docker-managed volumes. Output: DRIVER local VOLUME NAME my-data . Verifies volume creation. |
docker volume inspect <name> | Shows volume details | docker volume inspect my-data | Displays metadata like Mountpoint (host path), useful for debugging or understanding storage location. |
docker volume rm <name> | Removes a volume | docker volume rm my-data | Deletes an unused volume. Use after stopping/removing containers using it. |
docker run -v <volume_name>:<container_path> | Mounts a volume into a container | docker run -d -v my-data:/data --name my-container ubuntu sleep infinity | Mounts my-data to /data in the container. sleep infinity keeps Ubuntu running (fixes your earlier issue). |
docker run -v <host_path>:<container_path> | Creates a bind mount | docker run -d -v /home/ritesh/my-data:/app --name my-nginx nginx | Maps host path /home/ritesh/my-data to container’s /app . Alternative: --mount type=bind,source=/home/ritesh/my-data,target=/app . |
docker exec -it <container_name> /bin/bash | Opens a shell in a running container | docker exec -it my-container /bin/bash | Allows you to interact with the container’s filesystem to create/test files in the volume. |
docker stop <container_name> | Stops a container | docker stop my-container | Gracefully stops a running container. |
docker rm <container_name> | Removes a container | docker rm my-container | Deletes a stopped container, but volume data persists. |
docker ps | Lists running containers | docker ps | Verifies containers are running before docker exec . |
docker ps -a | Lists all containers (running/stopped) | docker ps -a | Checks for exited containers (e.g., your Ubuntu issue). |
mkdir <host_path> | Creates a host directory for bind mounts | mkdir ~/my-data | Prepares a host directory for bind mounting. |
🧪 Practice: Hands-on Tasks
Let’s get hands-on with two tasks to master Docker volumes and bind mounts. Follow these steps to create, use, and verify persistent storage. Each task includes commands, expected outputs, and explanations to ensure success.
Task 1: Create and Use a Docker Volume 💾
Goal: Create a Docker-managed volume, store a file, and verify it persists across container lifecycles.
Create a Volume:
docker volume create my-data docker volume ls
Output:
DRIVER VOLUME NAME local my-data
Explanation: Creates a volume named
my-data
in Docker’s storage directory. Verify withls
.Run a Container with the Volume:
docker run -d -v my-data:/data --name my-container ubuntu sleep infinity docker ps
Output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES <id> ubuntu "sleep infinity" 2 seconds ago Up 2 seconds my-container
Explanation: Mounts
my-data
to/data
in the container.sleep infinity
prevents the container from exiting (fixing your earlier issue).Create a File in
/data
:docker exec -it my-container /bin/bash echo "Hello, Docker!" > /data/test.txt cat /data/test.txt exit
Output (
cat
):Hello, Docker!
Explanation: Createstest.txt
in/data
, which is backed by themy-data
volume. The file persists outside the container.Test Persistence:
docker stop my-container docker rm my-container docker run -d -v my-data:/data --name new-container ubuntu sleep infinity docker exec -it new-container /bin/bash cat /data/test.txt exit
Output (
cat
):Hello, Docker!
Explanation: Removes the original container and runs a new one with the same volume. The file persists, proving volume durability.Clean Up:
docker stop new-container docker rm new-container docker volume rm my-data # Optional
Explanation: Removes containers and (optionally) the volume to free resources.
Key Takeaway: Docker volumes ensure data persistence, critical for apps like MongoDB in your project.
Task 2: Bind Mount 🌉
Goal: Map a host directory to a container and verify two-way file synchronization.
Create a Host Directory:
mkdir ~/my-data ls ~
Output:
my-data
(among other files) Explanation: Creates/home/ritesh/my-data
for the bind mount.Run a Container with a Bind Mount:
docker run -d -v /home/ritesh/my-data:/app --name my-nginx nginx docker ps
Output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES <id> nginx "/docker-entrypoint.…" 2 seconds ago Up 2 seconds 80/tcp my-nginx
Alternative (if
-v
fails):docker run -d --mount type=bind,source=/home/ritesh/my-data,target=/app --name my-nginx nginx
Explanation: Maps
/home/ritesh/my-data
to/app
in the container. Use-v
ortype=bind
to avoid your previous “invalid characters” error.Add a File on the Host:
echo "Hello from the host!" > ~/my-data/host-file.txt cat ~/my-data/host-file.txt
Output:
Hello from the host!
Explanation: Creates a file in the host directory, which should appear in the container’s/app
.Verify in the Container:
docker exec -it my-nginx /bin/bash cat /app/host-file.txt echo "Hello from the container!" > /app/container-file.txt exit
Output (
cat
):Hello from the host!
Explanation: Confirms the host file is visible in/app
. Creates a container file to test synchronization.Verify on the Host:
ls ~/my-data cat ~/my-data/container-file.txt
Output:
host-file.txt container-file.txt Hello from the container!
Explanation: The container’s file appears on the host, proving two-way sync.
Clean Up:
docker stop my-nginx docker rm my-nginx rm -r ~/my-data # Optional
Explanation: Removes the container. The host directory persists unless deleted.
Key Takeaway: Bind mounts enable real-time file syncing, ideal for development workflows (e.g., Flask code).
🔍 Troubleshooting Tips
Container Exits Immediately 🚨:
Issue: Ubuntu containers exit with
/bin/bash
in detached mode (as seen in your output).Fix: Use
sleep infinity
:docker run -d -v my-data:/data --name my-container ubuntu sleep infinity
Verify:
docker ps
(running) ordocker ps -a
(exited).
Bind Mount Error (e.g., "invalid characters") ⚠️:
Issue: Docker misinterprets the host path as a volume name (your recent error).
Fix: Use
-v
or explicit--mount type=bind
:docker run -d -v /home/ritesh/my-data:/app nginx
or
docker run -d --mount type=bind,source=/home/ritesh/my-data,target=/app nginx
Permission Issues 🔒:
Issue:
Permission denied
when accessing bind mount files.Fix: Adjust host permissions (for practice):
chmod -R 777 /home/ritesh/my-data
Warning: Avoid
777
in production.
Path Errors 🛤️:
Fix: Verify the host path:
ls /home/ritesh/my-data echo $HOME # Should be /home/ritesh
🌟 Additional Notes
Docker Volumes vs. Bind Mounts:
Volumes: Production-ready, managed by Docker (e.g., MongoDB
/data/db
).Bind Mounts: Development-friendly, direct host access (e.g., Flask code).
Project Relevance: Use volumes for MongoDB data and bind mounts for Flask code in your Day 31–33 project.
Performance: Volumes are faster on Linux; bind mounts may be slower on macOS/Windows.
Resources:
🚀 Extended Practice (Optional)
Share a Volume Across Containers:
docker volume create shared-data docker run -d -v shared-data:/data --name c1 ubuntu sleep infinity docker run -d -v shared-data:/data --name c2 ubuntu sleep infinity docker exec -it c1 /bin/bash echo "Shared file" > /data/shared.txt exit docker exec -it c2 /bin/bash cat /data/shared.txt # Output: Shared file
Custom Nginx Page with Bind Mount:
echo "<h1>My Custom Page</h1>" > ~/my-data/index.html docker run -d -p 8080:80 -v /home/ritesh/my-data:/usr/share/nginx/html --name my-nginx nginx
Open
http://localhost:8080
to see “My Custom Page”.
👨💻 Author
Subscribe to my newsletter
Read articles from Ritesh Singh directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Ritesh Singh
Ritesh Singh
Hi, I’m Ritesh 👋 I’m on a mission to become a DevOps Engineer — and I’m learning in public every single day.With a full-time commitment of 8–10 hours daily, I’m building skills in: ✅ Linux✅ Git & GitHub✅ Docker & Kubernetes✅ AWS EC2, S3✅ Jenkins, GitHub Actions✅ Terraform, Prometheus, Grafana I post daily blogs on Hashnode, push projects to GitHub, and stay active on LinkedIn and Twitter/X. Let’s connect, collaborate, and grow together 🚀 #100DaysOfDevOps #LearningInPublic #DevOps