Using volumes in Docker Compose
Purpose
The purpose of this post is to review how we can use volumes in Docker and Docker Compose. These are some possible scenarios:
- Use one/various volumes by one service/container.
- Use one/various volumes by one set of services (defined in the same docker-compose.yml file).
- Use one/various volumes across the Docker installation.
Before you begin
In this tutorial, we’ll learn how to use Docker Compose volumes. A GNU Linux/Mac OS/Windows machine with Docker and Docker Compose installed is required to follow this tutorial.
How to declare volumes in Docker
There are two ways of declaring volumes in Docker: The imperative way (Docker client) and the declarative way (Docker Compose yaml file or Docker Dockerfile).
In the this post you’ll see only how to do it in a declarative manner using a docker-compose file. But it’s worth mention that is also possible to declare volumes in Docker using their command line client:
docker volume create [OPTIONS] [VOLUME]
Types of volumes in Docker
1. Docker host-mounted volumes
Syntax: /host/path
:/container/path
Host path can be defined as an absolute or as a relative path.
Example:
version '3'
services:
app:
image: nginx:alpine
ports:
- 80:80
volumes:
- /var/opt/my_website/dist:/usr/share/nginx/html:ro
2. Docker named volumes
Syntax: named_volume_name
:/container/path
Named volumes can be defined as internal (default) or external.
2.1. Docker internal named volumes
Docker compose internal named volumes have the scope of a single Docker-compose file and Docker creates them if they don’t exist.
Docker Compose file example with a named volume web_data
:
version '3'
volumes:
web_data:
services:
app:
image: nginx:alpine
ports:
- 80:80
volumes:
- web_data:/usr/share/nginx/html:ro
TIP 1: From Docker Compose version 3.4 the name of the volume can be dynamically generated from environment variables placed in an .env file (this file has to be in the same folder as docker-compose.yml is).
TIP 2: To increase the security in our system we can mount the volume as read-only if the container only needs to read the mounted files. This will prevent an attacker to modify or create new files in the host of the server for example.
Example of .env file:
VOLUME_ID=my_volume_001
Example of a Docker Compose file with and internal docker named volume based on an environment variable:
version '3.4'
volumes:
web_data:
name: ${VOLUME_ID}
services:
app:
image: nginx:alpine
ports:
- 80:80
volumes:
- web_data:/usr/share/nginx/html:ro
docker-compose up
will generate a volume called my_volume_001.
2.2. Docker external named volumes
Docker compose external named volumes can be used across the Docker installation and they need to be created by the user (otherwise fails) using the docker volume create command.
Example:
Defines web_data
volume:
docker volume create --driver local \
--opt type=none \
--opt device=/var/opt/my_website/dist \
--opt o=bind web_data
docker-compose.yml file with a named volume web_data
defined externally:
version '3'
volumes:
web_data:
external: true
services:
app:
image: nginx:alpine
ports:
- 80:80
volumes:
- web_data:/usr/share/nginx/html:ro
There are different volume types like nfs, btrfs, ext3, ext4 and also 3rd party plugins to create volumes.
External named volumes can be defined dynamically from environment variables using a name section as we did in the previous example.
3. Sharing volumes
Syntax: --volumes-from container_name
We can start a new container using volumes defined in another. Similar to -v
or --volume
but without having to define a volume or mounting paths.
$ docker run -it --name [my_new_container] --volumes-from [another_container] [image:tag] [command]
Note: --volumes-from
make sense if we are using just Docker. For Docker-compose we can use top-level volumes as we did in previous section and make them available to more than one service. Example sharing web_data to app and app2:
version '3'
volumes:
web_data:
external: true
services:
app:
image: nginx:alpine
ports:
- 80:80
volumes:
- web_data:/usr/share/nginx/html:ro
app2:
image: nginx:alpine
ports:
- 8080:80
volumes:
- web_data:/usr/share/nginx/html:ro
Remove Docker volumes
If you followed this tutorial you might have lots of Docker populated volumes. If you need to delete them, you can use the following post to delete the existing Docker volumes running in your system.
Final thoughts
One of the main benefits of using Docker volumes is the ability of changing the content/configuration of a container without the need of recreating it.
You should take into account that if the content of a container will never change probably is better to copy content once you are building its Docker image.
Finally, if you need to provide changes to a container that has no volumes attached with it and it is not possible to recreate it, there is always the option of copy files directly to a running container.
Recommended books to expand your Docker knowledge:
DevOps books:
Cloud providers:

DigitalOcean offers affordable pricing for VMs and many other public cloud services. You can sign up for DigitalOcean and receive a $100 free credit using this referral link.