Hello! Welcome back to our module on "Advanced Networking and Data Persistence."
In our last lesson, we established the crucial differences between volumes, bind mounts, and tmpfs mounts. We concluded that named volumes are the preferred, most robust method for persisting data in production environments.
Today, we'll put that theory into practice. This lesson is dedicated to the full lifecycle of named volumes, covering how to create, manage, and, most importantly, share them between multiple containers. This is a foundational pattern for building multi-service applications, a common task in your role as a DevOps Engineer.
1. The Anatomy of a Named Volume
A named volume is a data storage unit managed by Docker that exists independently of any container's lifecycle. You interact with it using a human-readable name, and Docker handles the details of where it's stored on the host machine.
Let's start by learning the basic commands to manage these volumes.
The video 'Docker Volumes Explained' provides a very clear and concise walkthrough of the essential docker volume commands. It will show you how to create, list, inspect, and remove volumes.
Watch the section from 00:44 to 02:50. Pay attention to the commands docker volume create, docker volume ls, docker volume inspect, and docker volume rm.
As you saw, the core commands are straightforward:
docker volume create <volume_name>: Creates a new, named volume.docker volume ls: Lists all volumes on your system.docker volume inspect <volume_name>: Provides detailed information, including theMountpointon the host filesystem where the data is actually stored. While you can look at this directory, it's best practice to let Docker manage it.docker volume rm <volume_name>: Deletes a volume. This will fail if the volume is currently in use by a running container.
2. Attaching a Volume and Proving Persistence
Now that we can create a volume, let's attach it to a container to store data. We'll then demonstrate that the data persists even after the container is gone.
You can attach a volume using one of two flags: --volume (or -v) and --mount.
--volumesyntax:docker run -v <volume_name>:/path/in/container ...--mountsyntax:docker run --mount source=<volume_name>,target=/path/in/container ...
While -v is shorter, --mount is the more explicit and recommended syntax. It uses key-value pairs, which makes the command easier to read and allows for more advanced options that we'll encounter later.
Let's see this in action.
The same video provides an excellent hands-on demonstration of this concept. It shows how to create a container with a volume, modify a file within that volume, remove the container, and then launch a new container that re-attaches the same volume to see the changes persist.
Watch the segment from 04:09 to 07:41. Follow the steps of running an Nginx container, modifying the index.html file inside the volume, and verifying that the change persists in a new container.
This simple exercise is powerful. It confirms that the volume my-nginx-volume and the data inside it have a lifecycle completely separate from any container that uses it.
3. Sharing a Single Volume Between Multiple Containers
This is where the real power of volumes comes into play for building applications. Many architectures require multiple services to access the same set of data. For example:
- A web server that saves user uploads to a directory.
- A backend worker service that reads from that same directory to process the uploaded files.
A shared named volume is the perfect solution for this.

Sharing via the Docker CLI
You can achieve this by simply running multiple containers and pointing them all to the same named volume using the --mount flag.
What is Docker Volume | How to create Volumes | What is Bind Mount | Docker Storage
To see a practical example of this, let's watch a segment from the 'What is Docker Volume' video. It demonstrates sharing a volume between two different Jenkins containers, a realistic scenario where you might want to share configuration or job data.
Watch the section from 08:18 to 11:11. Notice how two separate docker run commands are used, but both specify the same volume name (-v my-volume-one...). The result is that the job created in the first container is immediately visible in the second.
Sharing via Docker Compose
While the CLI approach works, in a professional DevOps context, you'll almost always define multi-service applications using Docker Compose. Compose makes sharing volumes between services incredibly simple and declarative.
How to Share Files Between Docker Containers Using Volumes
The article 'How to Share Files Between Docker Containers Using Volumes' provides excellent examples of how to do this in a docker-compose.yml file.
Read the sections 'Sharing a Volume Between Containers' and 'Docker Compose Volume Sharing'. Focus on the structure of the Compose file: a top-level volumes key is used to declare the named volume, and then each service mounts it under its own volumes section.
The key pattern in Docker Compose is:
- Declare a top-level
volumesblock: This is where you list the named volumes your application needs. - Mount the volume in each service: Under each service definition, use the
volumeslist to map the named volume to a path inside that service's container.
Here's a simple example based on the article, showing a web service and an api service sharing an uploads volume:
version: '3.8'
services:
web:
image: nginx
volumes:
- uploads:/var/www/html/uploads:ro # Mounts as read-only
api:
image: my-api
volumes:
- uploads:/app/uploads # Mounts as read-write
volumes:
uploads: # Declares the named volume 'uploads'
Notice the :ro (read-only) flag on the web service. This is a crucial security practice. If a service only needs to read data from a volume, you should always mount it as read-only to prevent accidental or malicious modifications.
Test your understanding!
You are building a system with two services defined in a docker-compose.yml file:
- A
producerservice that continuously writes log lines to a file at/app/data/events.log. - A
consumerservice that needs to read/app/data/events.logto process the logs.
Both services need to access the same events.log file. How would you structure your docker-compose.yml to achieve this using a shared named volume called log-data? Ensure the consumer cannot accidentally delete or modify the log file.
Show answer
Here is a correct docker-compose.yml structure:
version: '3.8'
services:
producer:
image: my-producer-app
# This service writes to the volume
volumes:
- log-data:/app/data
consumer:
image: my-consumer-app
# This service reads from the volume, so we use read-only
volumes:
- log-data:/app/data:ro
# Define the shared named volume at the top level
volumes:
log-data:
Key elements:
- A top-level
volumeskey defines the named volumelog-data. - Both
producerandconsumerservices mount this same volume. - The
consumerservice mounts the volume with the:roflag to ensure it has read-only access, following the principle of least privilege.
Conclusion
You've now mastered the practical skills for managing and sharing data between containers using named volumes. This is a critical building block for designing resilient, stateful, and multi-service applications with Docker.
Key Takeaways:
- Named volumes are Docker-managed persistent storage with a lifecycle independent of containers.
- You can manage volumes with the
docker volume create|ls|inspect|rmcommands. - A single named volume can be mounted into multiple containers, allowing them to share data.
- Docker Compose provides a declarative and simple way to define and share volumes among services in an application stack.
- Using read-only (
:ro) mounts is a best practice for services that only need to read data from a shared volume.
In our next lesson, we'll address a critical operational concern: implementing a backup and restore strategy for Docker volumes. After all, persistent data is only useful if you can protect it from loss.