Storage

** TODO you can also use files as bind mounts **

Docker provides volumes, a sort of virtual disk to store data and share it. There are two types of volumes, Persistent and Ephemeral. Volumes are not a part of images, but rather are local to hosts.

Further, docker provides bind mounts, which have limited functionality compared to volumes, and are commonly used with entire services (or swarms) rather than invididual containers. However, they become quite useful for individual containers in certain scenarios

Named Volumes

Creating Named Volumes

We can create arbitrary volumes using the following command:

$ docker volume create <VOLUME-NAME>

This will create a new volume inside of /var/lib/docker/volumes, which we can see from the command docker volume list:

The newly-created volume can be referenced by simply passing its name:

The newly-created docker container will have a folder named volume1 in its root directory, which is the mounted volume. We can also specify a directory within the container to mount the volume to:

$ docker run -ti --rm -d --name tester -v volume1:/shared-data ubuntu

volume1 can now be accessed through the shared-data directory within the container.

Managing Named Volumes

There are 5 major commands to manage named volumes

  1. docker volume create - creates a volume
  2. docker volume inspect - inspects a volume
  3. docker volume ls - lists all volumes
  4. docker volume prune - removes all unused local volumes
  5. docker volume rm - removes a volume

Sharing Data

When creating a volume, a new directory is created on the host machine within docker’s storage directory, and docker manages the contents of this directory.

Between docker VM and container

Sharing data between the host and the containers is easy with the use of Volumes.

MacOs and Windows

We need to connect to the Linux virtual machine to have a terminal running on the linux host

  1. Connect to the machine via SSH
$ docker-machine ssh
  1. Create a folder temp
$ mkdir temp
$ pwd temp

We’re now going to take the result of the pwd command and use it as an argument when creating a new container

Option 1: Specify host directory

  1. Create a new container
$ docker run -ti --rm --name tester -v /home/docker/temp:/shared-folder
  ubuntu bash

Now, inside of the new container, we will have shared-folder which connects to the folder /home/docker/temp on the docker virtual machine. Creating a file in this folder will create a file in /home/docker/temp.

Option 2: Don’t specify host directory

  1. Create a new container
$ docker run -ti -d --rm --name tester2 -v /shared-folder-2 ubuntu

Now if we run the command docker inspect tester2, we’ll come across the mounts key:

"Mounts": [
{
    "Type": "volume",
    "Name": "e270465b77cd981aa6655479bb5a199134fe55b657b14c1c0413a874498f0cfb",
    "Source": "/mnt/sda1/var/lib/docker/volumes/e270465b77cd981aa6655479bb5a199134fe55b657b14c1c0413a874498f0cfb/_data",
    "Destination": "/shared-folder2",
    "Driver": "local",
    "Mode": "",
    "RW": true,
    "Propagation": ""
}

Here, docker has automatically created a subdirectory of the docker storage directory on our host machine. Docker will manage this folder for us and delete it after all containers which mount it are removed.

This method is recommended, as the host root directory used in the first step is obviously not inherently portable, so it’s better to let docker manage the storage on its own.

Between Containers

For this we’ll use the volumes-from argument to docker run which will create a shared volume which will only exist in the scope that it is needed.

$ docker run -ti -v /shared-data --name test1 ubuntu bash

So we can now start a second container using the volumes-from parameter to share this shared-data folder:

$ docker run -ti --volumes-from test1 ubuntu bash

This new container will contain the shared-data folder, which it can add to or remove from. When the new container is killed, the files placed in shared-data will still exist in the test1 container.

The volume (including the shared-data folder) will remain until the final container which is using it is killed.

Bind Mounts

A bind mount is the process of mounting a directory from the host machine to the inside of a docker container. This directory is not (unlike volumes) created on-demand on the host machine if it does not already exist.

Note

Bind mounts can not be accessed or modified from the docker CLI.

Consider using named volumes instead.

Read Only

We can also specify that a volume or bind mount is read-only by passing readonly or ro when they are created

New Volume

Let’s try:

$ docker run -ti --rm -d --name test --mount destination=/shared-data,readonly ubuntu

The result?

docker: Error response from daemon: invalid mount config for type "volume": must not set ReadOnly mode when using anonymous volumes.
See 'docker run --help'.

This makes sense, as we would never create a new volume on the host machine only to set it to read-only.

Named Volume

$ docker run -ti --rm -d --name test --mount src=volume1,destination=/shared-data,readonly ubuntu

Bind Mount

$ docker run -ti --rm -d --name test --mount type=bind,src="$(pwd)"/temp,destination=/shared-data,readonly ubuntu