Understanding Docker Volumes
Let us understand data persistence in Dockers using examples to create, backup, migrate, and restore Docker Volumes.
Table of contents
Docker overview
Docker is an open platform for developing, shipping, and running your applications. It enables you to separate your applications from their infrastructure so you can deliver the software quicker than ever before. With Docker, you can manage the infrastructure of your app the same way you manage your applications which makes the entire process quite streamlined for developers. By using Docker’s methodologies for shipping, testing, and deploying code quickly, developers can reduce the delay between writing code and running it in production. This helps make the entire process both cost and time effective.
In simpler words, Docker is a tool designed to make it easier to create, deploy, and run applications with the help of containers. Containers allow a developer to wrap an application along with required components like libraries and other dependencies before shipping it all out as one package.
What are Docker Volumes?
Volumes are the preferred, and extensively used, mechanisms for persisting data generated by Docker containers. Docker volumes basically create a link between one of the local folders on the system and the folder on the docker container. These folders have data replication so that even if a container gets restarted/deleted at some point in time, you will still have access to the data that the container generated.
Volume Drivers let you store volumes on remote hosts or cloud providers. They are used to encrypt the contents of volumes or to add other functionalities. Using volume drivers, new volumes can have their content pre-populated by a container.
Docker volumes also facilitate data sharing between containers.
About this article
In this article we try to understand the concept of docker volumes by taking a few examples and implementing the same in this demo project.
So let’s get started!
Linking the host file system to the docker container virtual file system
Here, we will create a host folder/file, link it to the docker container folder, and test scenarios out to see how this works.
- First create a folder on your local system which will persist container folder data. Here, it is
$(pwd)/docker/docker_vol
in our demo example. Now run the following code snippet:
docker run --name volnginx -v <absolute_path>/docker/docker-vol/:/usr/share/nginx/html -p 8080:80 -d nginx
--name => name of the running container
-v => mounts volume/links /docker/docker-vol/ to /usr/share/nginx/html
-p => publish the container's port(80) to the host(8080)
-d => runs docker container in background in detached mode.
This will the link the two file systems.
As this is a nginx container, let's add our own static content to it.
docker_vol/index.html (on host):
Hello this is index.html
docker_vol/hello.html (on host):
Hello this is hello.html
Log into the container and view the shared file/folder content
docker exec -it volnginx /bin/bash
ls /usr/share/nginx/html
Now, view localhost:8080 and localhost:8080/hello.html.
Remove hello.html from host system. localhost:8080/hello.html will have no content to show.
Now, let's create a file from inside the docker container in the same shared folder. The same file will now be persisted on the host folder.
To provide the container only read-only permissions on the folder:
docker run --name volnginx -v <absolute_path>/docker/docker-vol/:/usr/share/nginx/html:ro -p 8080:80 -d nginx
This is an example of Mount Type: bind where we mount an existing file system to docker container.
This can be done as follows:
docker inspect volnginx
and view under the Mount object
...
"Mounts": [
{
"Type": "bind",
"Source": "<directory>/docker-vol/",
"Destination": "/usr/share/nginx/html",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
]
...
Creating named Docker Volume
If you don't want to create a directory or have an existing directory to work with, you can simply create a volume and attach it the container as follows:
docker volume create hello
docker run --name mynginx1 -v hello:/<directory inside the container>:ro -p 8080:80 -d <image>
Here, we create a volume called hello and simply attach it to run an instance of the image(here we use nginx again).
The directory of the image will be created on the following location:
/var/lib/docker/volumes/<vol_name>/_data
As previous example, we can go ahead and make changes to this directory and the same will be reflected in the file system of the container.
This is an example of Mount Type: volume type.
docker inspect mynginx1
show the following Mount object -
...
"Mounts": [
{
"Type": "volume",
"Name": "hello",
"Source": "/var/lib/docker/volumes/hello/_data",
"Destination": "/usr/share/nginx/html",
"Driver": "local",
"Mode": "ro",
"RW": false,
"Propagation": ""
}
]
...
Note: The directory the docker volume creates can easily be located in Linux systems.
Sharing Docker Volumes across Containers
This section is relatively easy as you can simply attach a single volume to a number of containers and thus, enable sharing of data between them.
docker run --name mynginx1 -v hello:/<directory inside the container>:ro -p 8080:80 -d <image>
docker run --name mynginx2 -v hello:/<directory inside the container>:ro -p 8081:80 -d <image>
These launched containers will use the same volumes.
If there are a number of volumes attached to the container and we require all the volumes from that container to be attached to a new one, we can simply use the following code:
docker run --name mynginx3 --volumes-from mynginx1 -p 8082:80 -d nginx
Backup, Restore, and Migration of Docker Volumes
Backup
- The contents of existing volume (hello) -
ls -la /var/lib/docker/volumes/hello/_data/
We create a backup directory
We share the existing volume into a new container along with the backup directory.
We create a compressed version of the existing/shared volume inside the backup container of the directory.
Thus making a copy of the compressed form onto the host system.
Finally, remove the new container after the work is done using (--rm).
mkdir ~/backup
docker run --rm --volumes-from mynginx1 -v ~/backup:/backup ubuntu bash -c "cd /usr/share/nginx/html && tar cvf /backup/container.tar ."
The content of ~/backup is container.tar.
Restore
Let us now the restore the contents into a new Docker Volume.
We follow a similar command as above.
docker run --rm -v newvol:/recover -v ~/backup:/backup ubuntu bash -c "cd /recover && tar xvf /backup/container.tar"
To view the contents of the newly created volume -
ls -la /var/lib/docker/volumes/newvol/_data/
Migrate
The created compressed folder can be transferred onto a different host via any file transferring mechanism like scp, rsync, etc. and can be restored there.
Using Volumes in Docker Compose
Docker Compose is a tool for defining and running multi-container Docker applications. With Compose, we use a YAML file to configure our application’s services. Then, with a single command, you create and start all the services from your configuration.
We can implement and define Volumes in docker-compse.yaml in a very basic way as follows:
version: '3.5'
services:
corporate:
image: corporate.thetopgeek:latest
volumes:
- <host_path>:<conatiner_path> ## for host-mounted volumes
- <named_volume>:<container path> ## for named volumes
Advantages of Docker Volumes
Docker volumes provide a great way to persist data.
The learning curve is not that steep.
Managing volumes can done from the Docker CLI or Docker API.
They are easy to backup, restore, and migrate.
Sharing data among containers is relatively simpler.
Hope this article helps setup Docker Volume and interests you to use it in your Docker environment and infrastructure.
Thank you and keep enjoying Docker !!🐳 😀
This is a part of a series of articles to help understand Docker better. Find the other articles as follows: