Volumes#

You have to use -v option of the docker run command to mount volume to container. In general you have to use following syntax:

docker run \
    -v <volume1>:<path in container1> \
    -v <volume2>:<path in container2> \
    ...

Sometimes it’s extremely useful to mount a specific folder but not a volume; you need to use folder name instead of volume name - this case is specific type of the volume and called bind mount.

Mount to container#

To mount volume to the container you have to use -v <volume name>:<path in container> option.


The following example creates a Docker container that mounts test_volume as folder and stores my_file with my message.

docker volume create test_volume &> /dev/null
docker run --rm -itd\
    --name test_container \
    -v test_volume:/folder alpine \
    sh -c "echo \"my message\" > /folder/my_file" &> /dev/null
sleep 3

After while that container stops and being removed. So there aren’t any containers yet.

docker ps -a
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

But data has been saved. We can show this by mounting the same volume as the temp folder. If we now check the files stored in temp - there will be my_file.

docker run --rm -it -v test_volume:/temp alpine ls temp
my_file

And it’ll store exactly the same content that we saved at the begining.

docker run --rm -it -v test_volume:/temp alpine cat /temp/my_file
my message

Don’t forget to remove test volume after all.

docker volume rm test_volume
test_volume

Bind mount#

Bind mount is a specific but extremely usefull type of volume. It’s a folder on the host specified by user to be mounted to the container.


In the following example creted folder temp_folder, mounted to container as temp_folder_inc_count folder.

Note here is specified --user $(id -u):$(id -g) to run container with same user notebook runned. It’ll garantee that commands in host will have full rights for modifying/deleting files created from container.

mkdir temp_folder

docker run \
    --user $(id -u):$(id -g) \
    -v $(pwd)/temp_folder:/temp_folder_in_cont \
    --rm -itd --name temp_example \
    ubuntu &> /dev/null

Now temp_folder on the host and temp_folder_in_count on the container are the same folders. So the file container_file created by the container will be accessible from the host and vice versa the file host_file created by the host will be accessible from the container.

docker exec temp_example \
    bash -c "echo \'hello from container\' >> temp_folder_in_cont/container_file"

echo "hello from host" >> temp_folder/host_file

Now let us check conatiner_file from host and host_file from container.

cat temp_folder/container_file
docker exec temp_example cat temp_folder_in_cont/host_file
'hello from container'
hello from host

Finally, don’t forget to clean the system of debris.

docker stop temp_example &> /dev/null
rm -r temp_folder

Read only mount#

By adding :ro to the path of the folder in container you can make it to be read only in the container.


In the following example we creating file ro_ex which have content original_data and mount that file to the container.

echo "original data" > ro_ex
docker run --rm -idt --name ro_ex \
    -v $(pwd)/ro_ex:/experimental/ro_ex:ro \
    ubuntu &> /dev/null

Now let us try to read and modify this file from the container.

docker exec ro_ex cat /experimental/ro_ex
docker exec ro_ex bash -c "echo \"modified data\" > /experimental/ro_ex"
original data
bash: line 1: /experimental/ro_ex: Read-only file system

So there is no problem reading the file, but the attempt to modify it was rejected.

The next cell confirms that you can keep the file unchanged.

cat ro_ex
original data

Keeping your system clean.

docker stop ro_ex &> /dev/null
rm -r ro_ex

Mounting .dockerignore files#

Even if you mount the file described in .dockerignore, we will still have it in the container.

In the following example, I create app/ignore_file.txt and mention it in dockerignore. Build image using this .dockerignore, but in container based on this image I mount app folder. And as a result I can see contents of ignore_file.txt regardless of what I specified in the .dockerignore.

%%bash
cd filesystem_example
mkdir app
echo "message in ignore_file.txt" > app/ignore_file.txt
echo "=====.dockerignore====="
echo "app/ignore_file.txt" > .dockerignore
cat .dockerignore
echo "=====dockerfile====="
echo "FROM ubuntu" > dockerfile
cat dockerfile

# build image with setted .dockerignore
docker build -t test_image &> /dev/null

# start container mountig file mentioned in .dockerignore
docker run --rm -itd --name ignore_ex\
    -v $(pwd)/app:/app\
    ubuntu &> /dev/null

echo "=====ignore-file from container====="
# make sure that this secret file is in the container
docker exec ignore_ex cat app/ignore_file.txt

docker stop ignore_ex &> /dev/null
docker rmi test_image &> /dev/null
rm -r app
rm .dockerignore
rm dockerfile
=====.dockerignore=====
app/ignore_file.txt
=====dockerfile=====
FROM ubuntu
=====ignore-file from container=====
message in ignore_file.txt

Volume by default#

Some containers create their own volumes by default when they run, so you may find that your entire hard drive is flooded.


For example yandex/clickhouse-server. Let’s list volumes available in your system.

docker volume ls
DRIVER    VOLUME NAME

Now run 3 clickhouse servers.

docker run -d --name db_1 --rm yandex/clickhouse-server &> /dev/null
docker run -d --name db_2 --rm yandex/clickhouse-server &> /dev/null
docker run -d --name db_3 --rm yandex/clickhouse-server &> /dev/null

There are 3 more new volumes.

docker volume ls
docker stop db_1 db_2 db_3 &> /dev/null
DRIVER    VOLUME NAME
local     2a663bcb67e10d518c9380ef736c2b3a2a2cdbc0762e75c1e0ade4692a211140
local     7bc74bac7549fda3ad02caee85febd8161c6c2072e7626464f87fc63cef0234d
local     49d77d54fa7a358281c696412d5fc9ef87d7c3e9acb12fe449befb72c9faf9df

So clickhouse creates volume for each new container.

Several volumes#

You can repeat -v option in docker run many times as you need.


Here is an example where we add multiple volumes to a Docker container.

Note that we specify the -u $(id -u):$(id -g) option to be able to work with files created in the container from the host.

mkdir dir1 dir2

docker run --rm -itd \
    -u $(id -u):$(id -g) \
    -v $(pwd)/dir1:/dir1 \
    -v $(pwd)/dir2:/dir2 \
    --name test_container \
    alpine
06634a5fcefb4dd7298c139e45b1d5f3cb031c9da2642f3f407dad1205e91a70

Now to be sure that everything is fine lets manipulate with created folders from containers.

docker exec test_container sh -c "echo \"message\" > /dir1/file_for_dir1"
docker exec test_container sh -c "echo \"message\" > /dir2/file_for_dir2"

And check that our manipulations are reflected on the host file system.

ls dir1
ls dir2
file_for_dir1
file_for_dir2

Finally don’t forget to clear cache from the system.

docker stop test_container
rm -r dir1 dir2
test_container