Docker Volumes Example
Each Docker container stores the data its processes need in that container. Unless we make the container store the data outside the container, which is extremely useful for when we don’t want to have the data layer we work with tied to the running container. That’s what we are going to see in this example, using Docker volumes.
For this tutorial, Linux Mint 18 and Docker version 1.12.3 have been used.
You may skip Docker installation and jump directly to the beginning of the example below.
1. Installation
Note: Docker requires a 64-bit system with a kernel version equal or higher to 3.10.
We can install Docker simply via apt-get
, without the need of adding any repository, just installing the docker.io
package:
sudo apt-get update sudo apt-get install docker.io
For more details, you can follow the Install Docker on Ubuntu Tutorial.
2. Understanding volumes
The containers, apart from the running services, also store all the data within it. This means that, if we remove the container, all the data that has been added or changed will be gone.
For some cases this might be fine, but for others, we may want to make the data persist outside the container. The clearest example can be a container running a database, for which perhaps we don’t want to store the data in the container where the database service is running, but in the file system of the host. Another use, for example, can be for sharing data among several containers.
Docker allows this using a concept named as “Data volumes”. Actually, is very simple: a volume is a file or directory that is mounted directly in the container. The concept is the same as the “mount” in Linux.
3. Mounting a directory from the host to the container
As we used databases as example for the brief explanation for Docker volumes, why not using one for our example?
Before anything, let’s create the directory that will be binded to the MySQL data directory, for example:
mkdir -p $(echo $HOME)/docker/mysql-data
If you are using an existing one, take into account that MySQL needs an empty directory for storing its data.
Now, let’s pull the MySQL image; it’s enough to pull the default tagged one:
docker pull mysql
For using data volumes, the difference comes when creating the container. For indicating to Docker that we are going to use a volume, we have to use the -v
(--volume
) option, with the following format:
docker run -v /host/path:/container/path
By default, MySQL stores its data in /var/lib/mysql
, so that’s the directory we have to bind:
docker run -d \ --name=mysql1 \ -v $(echo $HOME)/docker/mysql-data:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD=test \ mysql
(Note that we also passed a password for MySQL root user in the environmental variable MYSQL_ROOT_PASSWORD
).
We can check the volumes information, among other things, with the inspect
command. As the output is quite long, we can format it to just show the volumes information:
docker inspect --format '{{ index .Mounts }}' mysql1
Which, in my case, shows:
[{ /home/julen/docker/mysql-data /var/lib/mysql true rprivate}]
Returning to the container. now, host’s $HOME/docker/mysql-data
is mounted to container’s /var/lib/mysql
. If we now list the directory of the directory, we will see that there are several files and directories, which have been created by MySQL.
Let’s now make a little test to see that our data persistence is working, and that the data used in the container, is actually not dependent of it. For this, we will create a database with a table, and insert a row:
docker exec -it mysql1 /bin/bash mysql -u root -p
After entering the password we set and being in the MySQL console, we will create the database and the table, and some data:
CREATE DATABASE testdb; USE testdb; CREATE TABLE test(foo varchar(100)); INSERT INTO test VALUES('a value');
Let’s remove now the container:
docker rm -f mysql1
And, create another one, of course, mounting the data directory:
docker run -d \ --name=mysql2 \ -v $(echo $HOME)/docker/mysql-data:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD=test \ mysql
If we connect now to the database of this container, with the same commands as above (just replacing mysql1
with mysql2
, for the container name), we will see that the database already exists, and that the introduced data is still there:
USE testdb; SELECT * FROM test;
The output would be:
+---------+ | foo | +---------+ | a value | +---------+ 1 row in set (0.00 sec)
4. Summary
This example has shown how to use Docker volumes, which are really useful when we want to keep the data separated from the actual container. We have seen how does it work by creating a container with a database, deleting the container, creating another new one, and seeing how the created data persisted.