Volumes
Volumes are the preferred mechanism for persisting data generated by and used by Docker containers. While bind mounts are dependent on the directory structure and OS of the host machine, volumes are completely managed by Docker. Volumes have several advantages over bind mounts:
- Volumes are easier to back up or migrate than bind mounts.
- You can manage volumes using Docker CLI commands or the Docker API.
- Volumes work on both Linux and Windows containers.
- Volumes can be more safely shared among multiple containers.
- Volume drivers let you store volumes on remote hosts or cloud providers, to encrypt the contents of volumes, or to add other functionality.
- New volumes can have their content pre-populated by a container.
- Volumes on Docker Desktop have much higher performance than bind mounts from Mac and Windows hosts.
In addition, volumes are often a better choice than persisting data in a container’s writable layer, because a volume does not increase the size of the containers using it, and the volume’s contents exist outside the lifecycle of a given container.
If your container generates non-persistent state data, consider using a tmpfs mount to avoid storing the data anywhere permanently, and to increase the container’s performance by avoiding writing into the container’s writable layer.
Volumes use rprivate bind propagation, and bind propagation is not configurable for volumes.
Choose the -v or —mount flag
In general, —mount is more explicit and verbose. The biggest difference is that the -v syntax combines all the options together in one field, while the —mount syntax separates them. Here is a comparison of the syntax for each flag.
If you need to specify volume driver options, you must use —mount .
-v or —volume : Consists of three fields, separated by colon characters ( : ). The fields must be in the correct order, and the meaning of each field is not immediately obvious.
- In the case of named volumes, the first field is the name of the volume, and is unique on a given host machine. For anonymous volumes, the first field is omitted.
- The second field is the path where the file or directory are mounted in the container.
- The third field is optional, and is a comma-separated list of options, such as ro . These options are discussed below.
—mount : Consists of multiple key-value pairs, separated by commas and each consisting of a <key>=<value> tuple. The —mount syntax is more verbose than -v or —volume , but the order of the keys is not significant, and the value of the flag is easier to understand.
- The type of the mount, which can be bind , volume , or tmpfs . This topic discusses volumes, so the type is always volume .
- The source of the mount. For named volumes, this is the name of the volume. For anonymous volumes, this field is omitted. May be specified as source or src .
- The destination takes as its value the path where the file or directory is mounted in the container. May be specified as destination , dst , or target .
- The readonly option, if present, causes the bind mount to be mounted into the container as read-only. May be specified as readonly or ro .
- The volume-opt option, which can be specified more than once, takes a key-value pair consisting of the option name and its value.
Escape values from outer CSV parser
If your volume driver accepts a comma-separated list as an option, you must escape the value from the outer CSV parser. To escape a volume-opt , surround it with double quotes ( » ) and surround the entire mount parameter with single quotes ( ‘ ).
For example, the local driver accepts mount options as a comma-separated list in the o parameter. This example shows the correct way to escape the list.
The examples below show both the —mount and -v syntax where possible, and —mount is presented first.
Differences between -v and —mount behavior
As opposed to bind mounts, all options for volumes are available for both —mount and -v flags.
When using volumes with services, only —mount is supported.
Create and manage volumes
Unlike a bind mount, you can create and manage volumes outside the scope of any container.
Хранение данных в Docker

Важная характеристика Docker-контейнеров — эфемерность. В любой момент контейнер может рестартовать: завершиться и вновь запуститься из образа. При этом все накопленные в нём данные будут потеряны. Но как в таком случае запускать в Docker приложения, которые должны сохранять информацию о своём состоянии? Для этого есть несколько инструментов.
В этой статье рассмотрим docker volumes, bind mount и tmpfs, дадим советы по их использованию, проведём небольшую практику.
Особенности работы контейнеров
Прежде чем перейти к способам хранения данных, вспомним устройство контейнеров. Это поможет лучше понять основную тему.
Контейнер создаётся из образа, в котором есть всё для начала его работы. Но там не хранится и тем более не изменяется ничего важного. В любой момент приложение в контейнере может быть завершено, а контейнер уничтожен, и это нормально. Контейнер отработал — выкидываем его и собираем новый. Если пользователь загрузил в приложение картинку, то при замене контейнера она удалится.
На схеме показано устройство контейнера, запущенного из образа Ubuntu 15.04. Контейнер состоит из пяти слоёв: четыре из них принадлежат образу, и лишь один — самому контейнеру. Слои образа доступны только для чтения, слой контейнера — для чтения и для записи. Если при работе приложения какие-то данные будут изменяться, они попадут в слой контейнера. Но при уничтожении контейнера слой будет безвозвратно потерян, и все данные вместе с ним.

В идеальном мире Docker используют только для запуска stateless-приложений, которые не читают и не сохраняют данные о своём состоянии и готовы в любой момент завершиться. Однако в реальности большинство программ относятся к категории stateful, то есть требуют сохранения данных между перезапусками.
Поэтому нужны способы сделать так, чтобы важные изменяемые данные не зависели от эфемерности контейнеров и, как бонус, были доступными сразу из нескольких мест.
В Docker есть несколько способов хранения данных. Наиболее распространенные:
- тома хранения данных (docker volumes),
- монтирование каталогов с хоста (bind mount).
Особые типы хранения:
- именованные каналы (named pipes, только в Windows),
- монтирование tmpfs (только в Linux).

На схеме показаны самые популярные типы хранения данных для Linux: в памяти (tmpfs), в файловой системе хоста (bind mount), в томе Docker (docker volumes). Разберём каждый вариант.
Тома (docker volumes)
Тома — рекомендуемый разработчиками Docker способ хранения данных. В Linux тома находятся по умолчанию в /var/lib/docker/volumes/. Другие программы не должны получать к ним доступ напрямую, только через контейнер.
Тома создаются и управляются средствами Docker: командой docker volume create, через указание тома при создании контейнера в Dockerfile или docker-compose.yml.
В контейнере том видно как обычный каталог, который мы определяем в Dockerfile. Тома могут быть с именами или без — безымянным томам Docker сам присвоит имя.
Один том может быть примонтирован одновременно в несколько контейнеров. Когда никто не использует том, он не удаляется, а продолжает существовать. Команда для удаления томов: docker volume prune.
Можно выбрать специальный драйвер для тома и хранить данные не на хосте, а на удалённом сервере или в облаке.
Для чего стоит использовать тома в Docker:
- шаринг данных между несколькими запущенными контейнерами,
- решение проблемы привязки к ОС хоста,
- удалённое хранение данных,
- бэкап или миграция данных на другой хост с Docker (для этого надо остановить все контейнеры и скопировать содержимое из каталога тома в нужное место).
Монтирование каталога с хоста (bind mount)
Это более простая концепция: файл или каталог с хоста просто монтируется в контейнер.
Используется, когда нужно пробросить в контейнер конфигурационные файлы с хоста. Например, именно так в контейнерах реализуется DNS: с хоста монтируется файл /etc/resolv.conf.
Другое очевидное применение — в разработке. Код находится на хосте (вашем ноутбуке), но исполняется в контейнере. Вы меняете код и сразу видите результат. Это возможно, так как процессы хоста и контейнера одновременно имеют доступ к одним и тем же данным.
Особенности bind mount:
- Запись в примонтированный каталог могут вести программы как в контейнере, так и на хосте. Это значит, есть риск случайно затереть данные, не понимая, что с ними работает контейнер.
- Лучше не использовать в продакшене. Для продакшена убедитесь, что код копируется в контейнер, а не монтируется с хоста.
- Для успешного монтирования указывайте полный путь к файлу или каталогу на хосте.
- Если приложение в контейнере запущено от root, а совместно используется каталог с ограниченными правами, то в какой-то момент может возникнуть проблема с правами на файлы и невозможность что-то удалить без использования sudo.
Когда использовать тома, а когда монтирование с хоста
| Volume | Bind mount |
|---|---|
| Просто расшарить данные между контейнерами. | Пробросить конфигурацию с хоста в контейнер. |
| У хоста нет нужной структуры каталогов. | Расшарить исходники и/или уже собранные приложения. |
| Данные лучше хранить не локально (а в облаке, например). | Есть стабильная структура каталогов и файлов, которую нужно расшарить между контейнерами. |
Монтирование tmpfs
Tmpfs — временное файловое хранилище. Это некая специально отведённая область в оперативной памяти компьютера. Из определения выходит, что tmpfs — не лучшее хранилище для важных данных. Так оно и есть: при остановке или перезапуске контейнера сохранённые в tmpfs данные будут навсегда потеряны.
На самом деле tmpfs нужно не для сохранения данных, а для безопасности, полученные в ходе работы приложения чувствительные данные безвозвратно исчезнут после завершения работы контейнера. Бонусом использования будет высокая скорость доступа к информации.
Например, приложение в контейнере тормозит из-за того, что в ходе работы активно идут операции чтения-записи, а диски на хосте не очень быстрые. Если вы не уверены, в какой каталог идёт эта нагрузка, можно применить к запущенному контейнеру команду docker diff . И вот этот каталог смонтировать как tmpfs, таким образом перенеся ввод-вывод с диска в оперативную память.
Такое хранилище может одновременно работать только с одним контейнером и доступно только в Linux.
Общие советы по использованию томов
Монтирование в непустые директории
Если вы монтируете пустой том в каталог контейнера, где уже есть файлы, то эти файлы не удалятся, а будут скопированы в том. Этим можно пользоваться, когда нужно скопировать данные из одного контейнера в другой.
Если вы монтируете непустой том или каталог с хоста в контейнер, где уже есть файлы, то эти файлы тоже не удалятся, а просто будут скрыты. Видно будет только то, что есть в томе или каталоге на хосте. Похоже на простое монтирование в Linux.
Монтирование служебных файлов
С хоста можно монтировать любые файлы, в том числе служебные. Например, сокет docker. В результате получится docker-in-docker: один контейнер запустится внутри другого. UPD: (*это не совсем так. mwizard в комментариях пояснил, что в таком случае родительский docker запустит sibling-контейнер). Выглядит как бред, но в некоторых случаях бывает оправдано. Например, при настройке CI/CD.
Монтирование /var/lib/docker
Разработчики Docker говорят, что не стоит монтировать с хоста каталог /var/lib/docker, так как могут возникнуть проблемы. Однако есть некоторые программы, для запуска которых это необходимо.
Ключ командной строки для Docker при работе с томами.
Для volume или bind mount:
Команды для управления томами в интерфейсе CLI Docker:
Создадим тестовый том:
Вот он появился в списке:
Команда inspect выдаст примерно такой список информации в json:
Попробуем использовать созданный том, запустим с ним контейнер:
После самоуничтожения контейнера запустим другой и подключим к нему тот же том. Проверяем, что в нашем файле:
То же самое, отлично.
Теперь примонтируем каталог с хоста:
Docker не любит относительные пути, лучше указывайте абсолютные!
Теперь попробуем совместить оба типа томов сразу:
Отлично! А если нам нужно передать ровно те же тома другому контейнеру?
Вы можете заметить некий лаг в обновлении данных между контейнерами, это зависит от используемого Docker драйвера файловой системы.
Создавать том заранее необязательно, всё сработает в момент запуска docker run:
Посмотрим теперь на список томов:
Ещё немного усложним команду запуска, создадим анонимный том:
Такой том самоуничтожится после выхода из контейнера, так как мы указали ключ –rm.
Если этого не сделать, давайте проверим что будет:
Хозяйке на заметку: тома (как образы и контейнеры) ограничены значением настройки dm.basesize, которая устанавливается на уровне настроек демона Docker. Как правило, что-то около 10Gb. Это значение можно изменить вручную, но потребуется перезапуск демона Docker.
При запуске демона с ключом это выглядит так:
Однажды увеличив значение, его уже нельзя просто так уменьшить. При запуске Docker выдаст ошибку.
Если вам нужно вручную очистить содержимое всех томов, придётся удалять каталог, предварительно остановив демон:
Автор статьи: Александр Швалов, практикующий инженер Southbridge, Certified Kubernetes Administrator, автор и разработчик курсов Слёрм.
Docker 03: Handling Docker Volumes with Hands-on
The purpose of this tutorial is to explain how to handle volumes in Docker containers.
Volumes are the preferred mechanism for persisting data generated by and used by Docker containers. While bind mounts are dependent on the directory structure and OS of the host machine, volumes are completely managed by Docker. Volumes have several advantages over bind mounts:
- Volumes are easier to back up or migrate than bind mounts.
- You can manage volumes using Docker CLI commands or the Docker API.
- Volumes work on both Linux and Windows containers.
- Volumes can be more safely shared among multiple containers.
- Volume drivers let you store volumes on remote hosts or cloud providers, to encrypt the contents of volumes, or to add other functionality.
- New volumes can have their content pre-populated by a container.
- Volumes on Docker Desktop have much higher performance than bind mounts from Mac and Windows hosts.
In addition, volumes are often a better choice than persisting data in a container’s writable layer, because a volume does not increase the size of the containers using it, and the volume’s contents exist outside the lifecycle of a given container.
Docker has two options for containers to store files in the host machine, so that the files are persisted even after the container stops: volumes, and bind mounts. If you’re running Docker on Linux you can also use a tmpfs mount.
- Volumes are stored in a part of the host file system which is managed by Docker (/var/lib/docker/volumes/ on Linux). Non-Docker processes should not modify this part of the file system. Volumes are the best way to persist data in Docker.
- Bind mounts may be stored anywhere on the host system. They may even be important system files or directories. Non-Docker processes on the Docker host or a Docker container can modify them at any time.
- tmpfs mounts are stored in the host system’s memory only, and are never written to the host system’s file system.
If your container generates non-persistent state data, consider using a tmpfs mount to avoid storing the data anywhere permanently, and to increase the container’s performance by avoiding writing into the container’s writable layer.
By default, all files created inside a container are stored on a writable container layer. This means that the data doesn’t persist when that container no longer exists.
Docker volumes, which are special directories in a container, store files in the host machine so that the files are persisted even after the container stops.
Create and manage volumes
Volumes are created and managed by Docker. You can create a volume explicitly using the docker volume create command.
$ docker volume create firstvolume
When you create a volume, it is stored within a directory on the Docker host. When you mount the volume into a container, this directory is what is mounted into the container. Look at the Mountpoint.
$ docker volume inspect firstvolume
Declaration of volumes
Volumes can be declared on the command-line, with the — volume or -v flag for docker run. Let’s create an alpine container.
$ docker run -it -v firstvolume:/sample alpine sh
Tip:
-v or — volume: Consists of three fields, separated by colon characters (:). The fields must be in the correct order.
- the first field is the name of the volume, and is unique on a given host machine. In this example volume name is firstvolume.
- The second field is the path where the file or directory are mounted in the container. In this example folder in container is /sample.
- The third field is optional, and is a comma-separated list of options, such as ro (read only).
Alpine:
- Alpine Linux is an independent, non-commercial, general-purpose Linux distribution designed for power users who appreciate security, simplicity and resource efficiency.
- Because of its small size, it is commonly used in containers providing quick boot-up times.
When we type ls command in alpine terminal, we can see the sample folder.
We create a file in the sample folder and exit.
$ echo "this is added in first container" > file.txt
We remove the alpine container.
$ docker container ps -a
$ docker container m [container ID]
Let’s check the file1.txt.
$ docker volume inspect firstvolume
As we see above, file1.txt is still there even if we remove the container.
Usage volume with different containers
Let’s run an alpine image and this time we will create try1 folder instead of sample folder.
Docker: управление вашими данными

В этой статье будет рассмотрен вопрос управления данными внутри контейнеров Docker, совместное использование данных разными контейнерами, а также резервное копирование этих данных.
- Docker тома (Docker volumes)
- Контейнеры Docker томов (Docker volume containers)
Но прежде чем рассказать о них чуть подробнее, необходимо еще раз обратить ваше внимание на то, как работает файловая система в контейнерах Docker. Образы Docker, из которых запускаются контейнеры, представляют собой последовательность неизменяемых (только чтение) слоев. Набор этих слоев, можно посмотреть при помощи команды docker history, например, для контейнера nginx версии latest это делается так:
Полный вывод истории образа можно получить, добавив к последней команде ключ —no-trunc. А еще детализацию любого образа можно посмотреть воспользовавшись проектом https://imagelayers.io.
При запуске из образа нового контейнера к этому набору неизменяемых слоев присоединяется слой, который можно изменять. С этого момента, если в контейнере попытаться изменить какой-нибудь существующий файл, то этот файл будет скопирован из одного из нижележащих неизменяемых слоев, в котором он был создан, в изменяемый слой, куда и запишутся все его изменения. Версия изменяемого слоя скрывает нижележащий файл, но не удаляет его. Когда вы удаляете запущенный контейнер и перезапускаете его из того же образа, все ваши изменения будут потеряны. Так работает UnionFS, которую использует Docker, для организации своей работы с данными.
Для того, чтобы иметь возможность сохранять ваши данные, а также использовать эти данные несколькими контейнерами, Docker предоставляем вам возможность использовать так называемые тома (Docker volumes). Если совсем просто, то тома — это обычные директории (или файлы) хостовой файловой системы сервера, на котором работает Docker, монтируемые в любую директорию контейнера.
Существует несколько способов инициализировать тома, у которых есть несколько важных отличий, которые необходимо понимать. Самый прямой способ — это определить использование тома контейнером при его запуске при помощи флага -v:
Данная команда запустит контейнер с именем nginx_example именем хоста контейнера (-h) nginx-container из образа nginx в интерактивном режиме работы (-it), передаст управление интерпретатору /bin/bash, предварительно создав безымянный том (-v) и смонтировав его в /opt/static. При этом в директория /opt/static будет создана автоматически, она будет жить вне UnionFS и будет доступна для записи внутри контейнера, т.е. все файлы, которые вы сохраните в этой директории будут помещены внутрь тома. Вы можете определить расположение тома на файловой системе хостового сервера, на котором работает Docker, при помощи команды docker inspect:
В этом примере используется фильтр (-f) всего вывода docker inspect nginx_example, показывающий только часть содержимого, которое относится к блоку Mounts. При этом вывод форматируется утилитой jq.
После того, как мы знаем имя тома (ключ Name), мы можем получить ту же информацию при помощи команды
В обоих случаях вывод показывает вам, что Docker смонтировал /opt/static внутрь контейнера как директорию /var/lib/docker/volumes/e01cb937734c02790c94c14339bc563159a88c025e266d298d48398352ea477d/_data. Чтобы убедиться в этом, создайте, например, файл test на хостовом сервере, на котором запущен Docker, внутри этой директории.
А затем посмотрите на содержимое /opt/static внутри контейнера.
Если вы отключились от интерактивного режима работы с контейнером, выполните команду docker start для запуска контейнера с интерактивным (-ai) к нему подключением:
Вы увидели этот результат только потому что /opt/static — это всего лишь директория на хостовом сервере, которая была смонтирована внутрь контейнера.
Тот же самый эффект будет достигнут при использовании инструкции VOLUME в Dockerfile:
Еще один способ создавать тома — это использовать команду docker volume create:
Который в последствие может быть подключен к вашему контейнеру. Обратите внимание, том может быть подключен только к новому контейнеру, поэтому старый контейнер предварительно придется удалить:
Есть еще один часто используемый способ создания тома, реализуемый только при помощи параметра -v, монтирующий указанную директорию хостового сервера внутрь контейнера. Для этого создайте на хостовом сервере директорию folder_test, внутри этой директории файл test_file, а затем пересоздайте контейнер, указав полный путь до директории folder_test:
Как видите, содержимое директории folder_test стало доступно внутри запущенного контейнера. Этот способ работы с томами очень удобно использовать, например, в процессе разработке приложений. В целях сохранения свойства переносимости контейнеров, директория, использующаяся для тома на хостовом сервере, не может быть указана в Dockerfile (ведь эта директория совершенно не обязательно должна быть доступна во всех контейнерах). В случае использования этой формы работы с томами (монтирование тома при помощи флага -v в процессе создания контейнера) файлы, возможно содержащиеся внутри директории образа, не копируются внутрь тома (в данном случае в директорию на хостовом сервере). Docker не управляет такого рода томами как показано в прошлых примерах, и поэтому такие тома не появятся в выводе команды docker volume ls и никогда не будут удалены демоном Docker.