The purpose of this post is to review how we can use volumes in Docker Compose. These are some possible scenarios:
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.
There are two ways of declaring volumes in Docker:
In this post, you’ll see only how to do it in a declarative manner using a docker-compose file. But it’s worth mentioning that is also possible to declare volumes in Docker using their command-line client:
docker volume create [OPTIONS] [VOLUME]
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
Syntax:
named_volume_name:/container/path
Named volumes can be defined as internal (default) or external.
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
TIPS:
Example of .env file:
VOLUME_ID=my_volume_001
Example of a Docker Compose file with an 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.
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.
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 makes sense if we are using just Docker. For Docker-compose we can use top-level volumes as we did in the 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
If you followed this tutorial you might have lots of Docker populated volumes.
Either you need to remove unused volumes, the persisted data from a running container, or its configuration, you can use the following commands to remove a Docker volume:
First of all, you should list all current volumes:
$ docker volume ls
DRIVER VOLUME NAME
local named_volume
local 0a0bce5c74f249a9954120ce3d6cbc5fb388d1fadc27fd55c2a008d2c1bd8d1a
local 1e3f5e108a2e2542f018d0302f3d598bb90ded4cd604fed352c9530d30d35a56
...
Named volumes are defined by the user and there is no issue to identify them. Things change a little bit for auto-generated volumes. These volumes can be tricky to be identified and if you need to delete one of them from a known container you should try to locate it:
$ docker inspect containerid
...
"Mounts": [{volume 6d29ac8a196.. }{ ... }]
The volume name to be deleted is 6d29ac8a196..
$ docker volume rm [volume_name]
$ docker volume prune
# using --filter you can filter which unused volumes you want to delete as we did before with stopped containers and networks.
$ docker volume prune --filter 'NAME=VALUE'
One of the main benefits of using Docker volumes is the ability to change 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 s 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 to it and it is not possible to recreate it, there is always the option of copying files directly to a running container.