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

Ritesh SinghRitesh Singh
7 min read

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 🗄️

TypeDescriptionBest ForProsCons
Docker VolumesManaged by Docker, stored in /var/lib/docker/volumes/Production (e.g., MongoDB /data/db)Portable, Docker-managed, optimizedLess visibility into storage location
Bind MountsMaps a host directory/file to a container pathDevelopment (e.g., Flask code)Direct host access, easy editsLess 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! 🔧

CommandPurposeExampleExplanation
docker volume create <name>Creates a Docker-managed volumedocker volume create my-dataInitializes a volume in Docker’s storage (e.g., /var/lib/docker/volumes/my-data/_data). Use for persistent storage like MongoDB data.
docker volume lsLists all volumesdocker volume lsShows all Docker-managed volumes. Output: DRIVER local VOLUME NAME my-data. Verifies volume creation.
docker volume inspect <name>Shows volume detailsdocker volume inspect my-dataDisplays metadata like Mountpoint (host path), useful for debugging or understanding storage location.
docker volume rm <name>Removes a volumedocker volume rm my-dataDeletes an unused volume. Use after stopping/removing containers using it.
docker run -v <volume_name>:<container_path>Mounts a volume into a containerdocker run -d -v my-data:/data --name my-container ubuntu sleep infinityMounts 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 mountdocker run -d -v /home/ritesh/my-data:/app --name my-nginx nginxMaps 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/bashOpens a shell in a running containerdocker exec -it my-container /bin/bashAllows you to interact with the container’s filesystem to create/test files in the volume.
docker stop <container_name>Stops a containerdocker stop my-containerGracefully stops a running container.
docker rm <container_name>Removes a containerdocker rm my-containerDeletes a stopped container, but volume data persists.
docker psLists running containersdocker psVerifies containers are running before docker exec.
docker ps -aLists all containers (running/stopped)docker ps -aChecks for exited containers (e.g., your Ubuntu issue).
mkdir <host_path>Creates a host directory for bind mountsmkdir ~/my-dataPrepares 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.

  1. 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 with ls.

  2. 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).

  3. 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: Creates test.txt in /data, which is backed by the my-data volume. The file persists outside the container.

  4. 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.

  5. 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.

  1. Create a Host Directory:

     mkdir ~/my-data
     ls ~
    

    Output: my-data (among other files) Explanation: Creates /home/ritesh/my-data for the bind mount.

  2. 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 or type=bind to avoid your previous “invalid characters” error.

  3. 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.

  4. 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.

  5. 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.

  6. 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) or docker 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)

  1. 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
    
  2. 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

Ritesh Singh
🌐 LinkedIn | 📝 Hashnode | GITHUB

0
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