Usually, if you delete a docker container, the data held within the container is lost – which is where docker volumes and bind mounts come in. A docker volume allows you to store files on the docker host machine, which are also mounted in the container – this means that the files will still be available on the host once the container has been stopped or deleted.
In this article, we will look at the two ways of persisting data, and go through some examples of how they can be used.
Options for Persisting Data in Docker Containers
There a many reasons why you would want to persist container data. Examples of data you likely want to keep include:
- Application Logs / Data
- Configuration files
- Postgres databases and configuration
- mysql data and configuration
- web server files / html / config
Docker Volume vs Bind Mount
There are two ways to save/persist data from docker containers by mounting storage from the docker host system. These are:
- Docker Volumes – These are stored on the host file system that docker manages. On my Centos system this is /var/lib/docker/volumes.
- Bind Mounts – These allow storage to be mounted from anywhere on the host system. For example: /home/user/docker. You could even mount /etc – but not a good idea! If you did so the container would be able to modify files in that location!
Volumes are usually the best option as non-docker processes shouldn’t be interacting with the data in /var/lib/docker/volumes. With bind mounts, you can mount any area on the host meaning that the docker host and docker container could both modify the files within.
How to Create a Docker Volume
A docker volume can be created using the docker volume create command. For example:
$ docker volume create test-vol
List Docker Volumes and Inspect Docker Volumes
The docker volumes on the host can be listed with the docker volume list command:
$ docker volume list DRIVER VOLUME NAME local test-vol
The output will show the name of the volume, and the driver used (more about that later). We can get more information on a docker volume by using the docker inspect command:
$ docker inspect test-vol
The mountpoint attribute shows the location of the volume and the data within. We can go to this location and create a file:
$ cd /var/lib/docker/volumes/test-vol/_data
$ touch testfile.txt
Using Volumes with Docker Containers
When starting a docker container you can either use an existing volume, or you can have a volume be created when the container is created. A volume can be added to a container by using either the -v or the –mount flag. You can read about both here, but I will be using the -v option.
$ docker run -it --name nginxtest -v test-vol:/data nginx:latest /bin/bash
With this command, I have started a docker container using the nginx image and attached the test-vol container created earlier, which is mounted to /data. Now, in the bash shell of the container, we can see the data directory:
drwxr-xr-x. 2 root root 25 Jul 7 09:11 data
And within it we can see testfile.txt which we created on the docker host earlier:
root@461196a67560:/# cd data root@461196a67560:/data# ls testfile.txt
Running docker inspect against the nginxtest container, the output will show the mounts:
"Mounts": [ { "Type": "volume", "Name": "test-vol", "Source": "/var/lib/docker/volumes/test-vol/_data", "Destination": "/data", "Driver": "local", "Mode": "z", "RW": true, "Propagation": "" } ],
Note: This container was started using a volume that already existed. If we used a volume name that didn’t already exist then a new volume would have been created when the container started.
Using Volumes with Docker Services
You can also use volumes with Docker services. When creating the service you can use the –mount flag:
$ docker service create -d --replicas=4 --name nginx-service --mount source=test-vol,target=/app nginx:latest
Note that using this method, a volume will be created on each docker swarm node that runs a replica of the service. A different way to do this is to use a shared volume.
Shared Docker Volumes
To use a shared docker volume we need to use a different volume driver. One example of which is the vieux/sshfs driver (you can also use an NFS driver) – this allows a docker host to access a volume remotely. For this to work, you first have to install the volume driver onto each docker host that needs access to the volume:
$ docker plugin install --grant-all-permissions vieux/sshfs
We can then create a volume using this volume driver. For example:
$ docker volume create --driver vieux/sshfs -o sshcmd=testuser@dockernode:/data -o password=mypassword test-vol
Notice that this is a little like establishing an SSH session or using SCP. In the command we include the host (dockernode) the user (testuser), the path (/data) and the password. We can then mount the volume when starting a container, which is the same command as when mounting a local volume:
$ docker run -d --name nginxtest -v test-vol:/data nginx:latest
As with local volumes, we can also create a shared volume when creating a comtainer:
$ docker run -d \ --name nginx-servertest \ --volume-driver vieux/sshfs \ --mount src=test-vol,target=/data,volume-opt=sshcmd=testuser@172.31.119.237:/docker/storage,volume-opt=password=mypassword \ nginx:latest
A common use to using a docker shared volume is with a docker swarm service. We can create a service using a shared volume with:
docker service create -d \ --replicas=3 \ --name nginx-web \ -p 8081:80 \ --mount volume-driver=vieux/sshfs,source=nginx-vol,target=/data,volume-opt=sshcmd=myuser@172.31.119.237:/docker/storage,volume-opt=password=mypassword nginx:latest
This service has created 3 nginx containers, all with a volume mapped to the same shared location, meaning that they could all share the same configuration or html content. Awesome!
Read Only Docker Volumes
You can mount a volume to a container as read only by including ‘readonly’ when attaching the volume. For example:
$ docker run -d \ --name=nginxserver \ --mount source=nginx-volume,destination=/usr/share/nginx/html,readonly \ nginx:latest
This is useful for files that you don’t want the container to be able to change. For example, config files and web content.
How to Delete a Docker Volume
A docker volume can be removed using the docker volume rm command:
$ docker volume rm test-vol
Bind Mounts
As mentioned earlier, a bind mount allows you to mount any area of the host file system to a docker container. The syntax for doing this is to specify the path on the host system, rather than a volume name:
$ docker run -d --name nginxtest --mount type=bind,source=/data,target=/appdata nginx:latest
You can also do a read only bind mount using:
$ docker run -d --name nginxtest --mount type=bind,source=/data,target=/appdata,readonly nginx:latest
Read a lot more about bind mounts here.
Final Thoughts
Hopefully this has helped your understanding of docker volumes and how they can be used. Examples have been shown on how to create docker volumes and bind mounts, shared docker volumes and read only volumes. As always, check out the official documentation, links below, for a more detailed explanation of these topics.