Lesson 3.2: Volumes
Welcome to Lesson 3.2! Now that you understand the ephemeral nature of containers, it's time to learn about volumes – Docker's recommended solution for persistent data. Volumes are managed by Docker, independent of the container lifecycle, and provide a clean, portable way to store and share data across containers. By the end of this lesson, you'll be able to use volumes to persist data, share data between containers, and manage your volume lifecycle effectively.
Learning Objectives
TIP
By the end of this lesson, you will be able to:
- Create and manage Docker volumes using CLI commands.
- Mount a volume into a container with the
-vor--mountflag. - Understand the difference between named volumes and anonymous volumes.
- List and inspect volumes with
docker volume lsanddocker volume inspect. - Remove unused volumes with
docker volume pruneanddocker volume rm. - Explain use cases for volumes (databases, stateful apps, sharing data between containers).
- Back up and restore data stored in volumes.
1. What Are Volumes?
A volume is a persistent data store managed by Docker. It exists outside the container's writable layer and is stored in a part of the host filesystem managed by Docker (typically /var/lib/docker/volumes/ on Linux). Volumes can be:
- Named: Given a specific name (e.g.,
my-data) for easy reference. - Anonymous: Automatically generated with a random ID when you don't specify a name.
Volumes have several advantages over bind mounts:
- Portability: Volume behavior is consistent across different Docker hosts (Docker Desktop, Linux, etc.).
- Backup and restore: Volumes can be backed up and restored using standard Docker commands.
- Management: Docker CLI provides commands to list, inspect, and prune volumes.
- Performance: On Linux, volumes leverage the native filesystem and bypass the storage driver, often providing better performance for write-heavy workloads.
- Security: Volumes are isolated from the host filesystem and can be managed with Docker's built-in permissions.
2. Working with Volumes
2.1. Creating Volumes
You can create a volume explicitly with docker volume create:
docker volume create mydataThis creates a named volume called mydata. If you don't specify a driver, it uses the local driver (the default).
2.2. Listing Volumes
docker volume lsYou'll see a list of all volumes, including anonymous ones. Example:
DRIVER VOLUME NAME
local mydata
local 0a3e2f1b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2.3. Inspecting a Volume
docker volume inspect mydataOutput is JSON containing the volume's name, driver, mountpoint (the path on the host where data is stored), and labels. The mountpoint is where you can directly access files from the host if needed.
3. Mounting Volumes into Containers
When you run a container, you can mount a volume using either the -v (or --volume) flag or the more explicit --mount flag. Both work, but --mount is preferred for clarity in scripts and Dockerfiles.
3.1. Using -v (Volume)
Syntax:
-v VOLUME_NAME:CONTAINER_PATH[:OPTIONS]VOLUME_NAMEcan be a named volume or an anonymous volume (if you omit a name, Docker creates an anonymous one).CONTAINER_PATHis where the volume is mounted inside the container.- Options:
rofor read-only,rwfor read-write (default),zorZfor SELinux labeling.
Example (named volume):
docker run -d --name db -v mydata:/var/lib/mysql mysql:8This mounts the volume mydata at /var/lib/mysql inside the container.
Example (anonymous volume):
docker run -d --name temp -v /data busybox sleep 3600This creates an anonymous volume (random name) mounted at /data.
3.2. Using --mount
The --mount flag is more explicit and recommended for automation.
Syntax:
--mount type=volume,source=VOLUME_NAME,target=CONTAINER_PATH[,readonly]type=volumeindicates a volume mount.sourceis the volume name (or for anonymous, you can omit source).targetis the mount point inside the container.readonly(optional) mounts as read-only.
Example:
docker run -d --name db --mount type=volume,source=mydata,target=/var/lib/mysql mysql:83.3. Mounting with Read-Only Access
To prevent the container from writing to the volume, add readonly to --mount or :ro to -v:
docker run -d --name app --mount type=volume,source=config,target=/config,readonly myapp4. Volumes in Practice: A Database Example
Let's run a MySQL container with a named volume to persist the database data.
Create a volume:
bashdocker volume create mysql-dataRun MySQL container using the volume:
bashdocker run -d --name mysql-db \ -e MYSQL_ROOT_PASSWORD=secret \ --mount type=volume,source=mysql-data,target=/var/lib/mysql \ mysql:8Check that MySQL is running and data is being written to the volume:
bashdocker logs mysql-dbStop and remove the container:
bashdocker stop mysql-db docker rm mysql-dbRun a new MySQL container with the same volume:
bashdocker run -d --name mysql-db-new \ -e MYSQL_ROOT_PASSWORD=secret \ --mount type=volume,source=mysql-data,target=/var/lib/mysql \ mysql:8The database will contain the same data as before because the volume persisted.
This pattern is essential for stateful services like databases, message brokers, or any application that writes to disk.
5. Sharing Volumes Between Containers
Volumes can be mounted into multiple containers simultaneously. This allows containers to share data. However, be careful with concurrent writes unless the application handles locking.
Example:
- Create a volume:bash
docker volume create shared-data - Run two containers that both mount the same volume:bash
docker run -d --name writer1 --mount type=volume,source=shared-data,target=/data busybox sh -c "while true; do echo $(date) >> /data/log.txt; sleep 5; done" docker run -d --name reader --mount type=volume,source=shared-data,target=/data busybox tail -f /data/log.txt - The
readercontainer will display the log entries written bywriter1.
6. Populating a Volume with Initial Data
When you mount a volume into a container, if the volume is empty and the container's target directory contains data, Docker copies the data from the image into the volume (but only if the volume is empty). This is useful for seeding a volume with default configuration or initial database content.
Example: If you mount an empty volume at /usr/share/nginx/html for an nginx container, nginx's default content will be copied into the volume. Subsequent runs will keep that content.
7. Managing Volumes
7.1. Removing Volumes
- Remove a specific volume:
docker volume rm VOLUME_NAME - Remove all unused volumes:
docker volume prune(interactive) - Force remove:
docker volume rm -f VOLUME_NAME(only if not in use)
Volumes cannot be removed if they are still in use by any container. You must stop and remove the containers first.
7.2. Backup and Restore Volumes
Since volumes are stored on the host, you can back up their contents by running a temporary container that mounts the volume and archives the data.
Backup example:
docker run --rm -v mydata:/data -v $(pwd):/backup alpine tar czf /backup/mydata-backup.tar.gz -C /data .-v mydata:/datamounts the volume to/data.-v $(pwd):/backupmounts the current directory to/backup.- The
tarcommand creates a compressed archive of/dataand saves it to/backup/mydata-backup.tar.gz.
Restore example:
docker run --rm -v mydata:/data -v $(pwd):/backup alpine sh -c "cd /data && tar xzf /backup/mydata-backup.tar.gz --strip 1"This extracts the backup into the volume.
8. Volume Drivers
Docker supports volume drivers that allow you to store volumes on remote systems (e.g., NFS, cloud storage, block storage). The default local driver stores volumes on the host filesystem. Third-party drivers (e.g., vsphere, azurefile, nfs) can be installed to provide advanced storage capabilities. This is an advanced topic, but worth knowing that volumes are not limited to local disk.
Hands-On Tasks
Task 1: Create and Use a Named Volume
- Create a volume named
app-data. - Run an Alpine container that writes a file to the volume, then exits.bash
docker run --rm -v app-data:/data alpine sh -c "echo 'Hello Volume' > /data/hello.txt" - Verify the file is in the volume by running another container that reads it:bash
docker run --rm -v app-data:/data alpine cat /data/hello.txt
Task 2: Inspect and Find Host Location
- Inspect the volume:
docker volume inspect app-data. - Note the
Mountpointfield. On Linux, go to that path and list the files. (On Docker Desktop, the path is inside the VM, but you can still see it withdocker run --rm -v app-data:/data alpine ls -l /data.)
Task 3: Database Persistence
- Create a volume
pg-data. - Run a PostgreSQL container using that volume (use
-e POSTGRES_PASSWORD=mysecretpassword). - Connect to the database and create a table.
- Stop and remove the container.
- Run a new PostgreSQL container with the same volume. Verify the table still exists.
Task 4: Share Data Between Two Containers
- Create a volume
shared. - Run a producer container that appends a line to a file every 5 seconds.
- Run a consumer container that tails the file.
- Verify that the consumer sees the logs.
Task 5: Volume Cleanup
- List all volumes with
docker volume ls. - Remove the volumes you created (except those still in use) using
docker volume rm. - Prune all unused volumes with
docker volume prune.
Task 6: Backup and Restore a Volume
- Create a volume
test-backupand put a file in it. - Perform a backup using a temporary container (as shown above).
- Delete the volume.
- Restore from the backup and verify the file is present.
Summary
Key Takeaways
- Volumes are Docker-managed persistent storage units, ideal for stateful containers.
- Use
docker volume createto create named volumes, or let Docker create anonymous volumes automatically. - Mount volumes with
-vor--mountwhen running containers. - Volumes survive container removal and can be shared among multiple containers.
- Manage volumes with
ls,inspect,rm, andprune. - Back up and restore volumes using temporary containers with
tar. - Volumes can be backed by different drivers for remote or specialized storage.
Check Your Understanding
- How do you create a named volume called
myvol? - What is the difference between a named volume and an anonymous volume?
- Write the
docker runcommand to mount a volume nameddbdataat/var/lib/mysqlinside a container, using--mount. - How can you mount a volume as read-only?
- What happens when you mount an empty volume into a container at a path that already contains data in the image?
- How do you back up a volume to a tar file?
Click to see answers
docker volume create myvol- A named volume has a user-specified name for easy reference and management. An anonymous volume has a randomly generated name and is harder to manage.
docker run -d --mount type=volume,source=dbdata,target=/var/lib/mysql mysql:8- Add
readonlyto--mountor:roto-v. - Docker copies the data from the image into the volume (seeding the volume with the image's initial content).
- Run a temporary container:
docker run --rm -v myvol:/source -v $(pwd):/backup alpine tar czf /backup/backup.tar.gz -C /source .
Additional Resources
- Docker volumes documentation
- Volume driver plugins
- docker volume CLI reference
- Backup and restore volumes
Next Up
In the next lesson, we'll cover Bind Mounts – a powerful alternative for development and configuration management. See you there!