# Understanding Docker Volumes

## 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**](https://docs.docker.com/storage/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**](https://docs.docker.com/storage/storagedriver/select-storage-driver/) 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 *<absolute_path>/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
```

![Screenshot 2022-03-30 at 7.16.35 AM.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1648604800223/0XaYU_4T3.png)

Now, view *http://localhost:8080* and *http://localhost:8080/hello.html*.

![Screenshot 2022-03-30 at 7.20.21 AM.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1648605027440/g1MKJIx5b.png)


![Screenshot 2022-03-30 at 7.20.42 AM.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1648605046750/2nRcq7tWP.png)

Remove *hello.html* from host system. *http://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.

![Screenshot 2022-03-30 at 7.26.36 AM.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1648605399759/L8dTdt6bR.png)

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/
```

![Screenshot 2022-04-03 at 1.46.43 PM.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1648973868254/eoUi48ApP.png)

- 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/
```

![Screenshot 2022-04-03 at 1.48.50 PM.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1648973957985/DzboM3yH_.png)

**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**](https://docs.docker.com/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:
- [Understanding Docker Networking](https://techblog.geekyants.com/understanding-docker-networking-1)
- [Understanding Docker Layers and Caching](https://techblog.geekyants.com/understanding-docker-layers-and-caching-1)
