Источник: How to mount a host directory in a Docker container
Автор вопроса использовал Docker version 0.9.1, build 867b2a9. Ниже приведён ответ для Docker версии 17.06 и новее.
Чтобы синхронизировать локальный каталог с каталогом внутри контейнера, подключите его как монтирование типа bind. Оно связывает исходный каталог в основной системе с целевым каталогом в Docker-контейнере. Это почти то же самое, что и обычное монтирование каталога в Linux.
Согласно документации Docker, теперь для монтирования рекомендуется использовать параметр --mount вместо -v. Он устроен следующим образом:
--mountсостоит из нескольких пар «ключ — значение», разделённых запятыми. Каждая пара имеет вид<key>=<value>. Синтаксис--mountподробнее, чем-vили--volume, но порядок ключей не имеет значения, а назначение параметров проще понять.typeзадаёт тип монтирования:bind,volumeилиtmpfs. В этой статье используетсяbind.sourceзадаёт источник монтирования. Для bind-монтирования это путь к файлу или каталогу на хосте, где работает демон Docker. Ключ можно записать какsourceилиsrc.destinationзадаёт путь внутри контейнера, куда будет смонтирован файл или каталог. Ключ можно записать какdestination,dstилиtarget.
Чтобы смонтировать текущий каталог (источник) в /test_container (цель), выполните:
$ docker run -it --mount src="$(pwd)",target=/test_container,type=bind k3_s3Если в параметрах монтирования есть пробелы, заключите их в кавычки. Если пробелов точно нет, вместо этого можно использовать `pwd`:
$ docker run -it --mount src=`pwd`,target=/test_container,type=bind k3_s3Также потребуется учитывать права доступа к файлам. Подробнее об этом рассказано в статье о правах доступа для томов Docker.
Изначально параметр -v, или --volume, использовался для отдельных контейнеров, а --mount — для сервисов Docker Swarm. Начиная с Docker 17.06 параметр --mount можно использовать и с отдельными контейнерами. Обычно его синтаксис более явный и подробный. Главное различие состоит в том, что синтаксис -v объединяет все параметры в одном поле, а --mount разделяет их. Ниже приведено сравнение синтаксиса этих параметров.
Совет. Новым пользователям рекомендуется синтаксис
--mount. Опытные пользователи могут быть лучше знакомы с-vили--volume, однако им также рекомендуется--mount, поскольку исследования показали, что этот синтаксис проще в использовании.
-vили--volumeсостоит из трёх полей, разделённых двоеточиями (:). Поля должны располагаться в правильном порядке, а назначение каждого из них не всегда очевидно.- При bind-монтировании первое поле содержит путь к файлу или каталогу на хосте.
- Второе поле содержит путь, по которому файл или каталог монтируется в контейнере.
- Третье поле необязательно. Оно содержит список разделённых запятыми параметров, например
ro,consistent,delegated,cached,zиZ. Эти параметры рассматриваются ниже.
--mountсостоит из нескольких разделённых запятыми пар<key>=<value>. Синтаксис--mountподробнее, чем-vили--volume, но порядок ключей не имеет значения, а назначение параметров проще понять.typeзадаёт тип монтирования:bind,volumeилиtmpfs. В этой статье рассматривается bind-монтирование, поэтому тип всегда равенbind.sourceзадаёт источник монтирования. Для bind-монтирования это путь к файлу или каталогу на хосте, где работает демон Docker. Ключ можно записать какsourceилиsrc.destinationзадаёт путь внутри контейнера, куда монтируется файл или каталог. Ключ можно записать какdestination,dstилиtarget.- Параметр
readonlyподключает монтирование к контейнеру в режиме только для чтения. - Параметр
bind-propagationизменяет распространение bind-монтирования. Допустимые значения:rprivate,private,rshared,shared,rslaveиslave. - Параметр
consistencyможет принимать значенияconsistent,delegatedиcached. Эта настройка применяется только в Docker Desktop для Mac и игнорируется на остальных платформах. - Параметр
--mountне поддерживаетzиZдля изменения меток SELinux.
В примерах ниже, где это возможно, показаны оба варианта синтаксиса. Вариант с --mount приводится первым.
Параметры -v и --volume давно входят в состав Docker, поэтому их поведение нельзя изменить. Из-за этого между -v и --mount есть одно важное различие.
Если с помощью -v или --volume выполнить bind-монтирование файла или каталога, которого ещё нет на хосте Docker, параметр -v создаст конечный объект. Он всегда создаётся как каталог.
Если с помощью --mount попытаться выполнить bind-монтирование файла или каталога, которого ещё нет на хосте Docker, Docker не создаст его автоматически, а вернёт ошибку.
Предположим, что у вас есть каталог source, а при сборке исходного кода артефакты сохраняются в другом каталоге — source/target/. Нужно, чтобы артефакты были доступны контейнеру в /app/, а после каждой сборки на хосте разработки контейнер получал доступ к её результатам.
Следующая команда выполняет bind-монтирование каталога target/ в /app/ внутри контейнера. Запустите её из каталога source. В Linux и macOS подкоманда $(pwd) подставляет текущий рабочий каталог.
Примеры с --mount и -v дают одинаковый результат. Их нельзя выполнить один за другим, не удалив контейнер devtest после первого запуска.
--mount
$ docker run -d \
-it \
--name devtest \
--mount type=bind,source="$(pwd)"/target,target=/app \
nginx:latest-v
$ docker run -d \
-it \
--name devtest \
-v "$(pwd)"/target:/app \
nginx:latestЧтобы убедиться, что bind-монтирование создано правильно, выполните docker inspect devtest и найдите раздел Mounts:
"Mounts": [
{
"Type": "bind",
"Source": "/tmp/source/target",
"Destination": "/app",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],Вывод показывает, что создано монтирование типа bind с правильными исходным и целевым путями. Оно доступно для чтения и записи, а для распространения задано значение rprivate.
Остановите и удалите контейнер:
$ docker container stop devtest
$ docker container rm devtestЕсли выполнить bind-монтирование в непустой каталог контейнера, существующее содержимое каталога будет скрыто подключённым монтированием. Это может быть полезно, например для тестирования новой версии приложения без сборки нового образа. Однако такое поведение может оказаться неожиданным и отличается от поведения томов Docker.
Следующий пример намеренно доведён до крайности: содержимое каталога /usr/ внутри контейнера заменяется содержимым каталога /tmp/ на хосте. В большинстве случаев после этого контейнер работать не сможет.
Примеры с --mount и -v дают одинаковый конечный результат.
--mount
$ docker run -d \
-it \
--name broken-container \
--mount type=bind,source=/tmp,target=/usr \
nginx:latest
docker: Error response from daemon: oci runtime error: container_linux.go:262:
starting container process caused "exec: \"nginx\": executable file not found in $PATH".-v
$ docker run -d \
-it \
--name broken-container \
-v /tmp:/usr \
nginx:latest
docker: Error response from daemon: oci runtime error: container_linux.go:262:
starting container process caused "exec: \"nginx\": executable file not found in $PATH".Контейнер будет создан, но не запустится. Удалите его:
$ docker container rm broken-containerВ некоторых сценариях разработки контейнер должен записывать данные в bind-монтирование, чтобы изменения передавались обратно на хост Docker. В других случаях контейнеру достаточно доступа только для чтения.
Следующий пример изменяет предыдущий: каталог подключается только для чтения. Для этого после точки монтирования внутри контейнера в список параметров, по умолчанию пустой, добавляется ro. Если параметров несколько, разделяйте их запятыми.
Примеры с --mount и -v дают одинаковый результат.
--mount
$ docker run -d \
-it \
--name devtest \
--mount type=bind,source="$(pwd)"/target,target=/app,readonly \
nginx:latest-v
$ docker run -d \
-it \
--name devtest \
-v "$(pwd)"/target:/app:ro \
nginx:latestЧтобы убедиться, что bind-монтирование создано правильно, выполните docker inspect devtest и найдите раздел Mounts:
"Mounts": [
{
"Type": "bind",
"Source": "/tmp/source/target",
"Destination": "/app",
"Mode": "ro",
"RW": false,
"Propagation": "rprivate"
}
],Остановите и удалите контейнер:
$ docker container stop devtest
$ docker container rm devtestПо умолчанию и для bind-монтирований, и для томов используется режим распространения rprivate. Настроить его можно только для bind-монтирований и только на хостах Linux. Распространение монтирования — сложная тема, и большинству пользователей не приходится его настраивать.
Распространение определяет, передаются ли монтирования, созданные внутри bind-монтирования или именованного тома, его копиям. Предположим, что точка /mnt также смонтирована в /tmp. Настройка распространения определяет, будет ли монтирование /tmp/a доступно также как /mnt/a.
У каждого режима распространения есть рекурсивный вариант. Предположим, что /tmp/a также смонтирован в /foo. В этом случае настройки распространения определяют, будут ли существовать /mnt/a и /tmp/a.
| Режим | Описание |
|---|---|
shared |
Подмонтирования исходного монтирования доступны его копиям, а подмонтирования копий также распространяются на исходное монтирование. |
slave |
Аналогичен shared, но действует только в одном направлении. Если в исходном монтировании появляется подмонтирование, оно доступно копии. Если подмонтирование появляется в копии, исходное монтирование его не видит. |
private |
Монтирование изолировано. Его подмонтирования не доступны копиям, а подмонтирования копий не доступны исходному монтированию. |
rshared |
Аналогичен shared, но распространение также охватывает точки монтирования, вложенные в любые исходные точки или их копии. |
rslave |
Аналогичен slave, но распространение также охватывает точки монтирования, вложенные в любые исходные точки или их копии. |
rprivate |
Значение по умолчанию. Аналогичен private: точки монтирования внутри исходного монтирования или его копий не распространяются ни в одном направлении. |
Прежде чем задавать распространение для точки монтирования, убедитесь, что файловая система хоста уже поддерживает эту возможность.
Подробнее см. в документации ядра Linux по общим поддеревьям.
Следующий пример дважды монтирует каталог target/ в контейнер. Для второго монтирования заданы и режим ro, и режим распространения rslave.
Примеры с --mount и -v дают одинаковый результат.
--mount
$ docker run -d \
-it \
--name devtest \
--mount type=bind,source="$(pwd)"/target,target=/app \
--mount type=bind,source="$(pwd)"/target,target=/app2,readonly,bind-propagation=rslave \
nginx:latest-v
$ docker run -d \
-it \
--name devtest \
-v "$(pwd)"/target:/app \
-v "$(pwd)"/target:/app2:ro,rslave \
nginx:latestТеперь при создании /app/foo/ также появится /app2/foo/.
При использовании SELinux параметры z и Z позволяют изменить метку SELinux файла или каталога на хосте, который монтируется в контейнер. Это влияет непосредственно на объект в основной системе и может иметь последствия за пределами Docker.
- Параметр
zозначает, что содержимое bind-монтирования используется совместно несколькими контейнерами. - Параметр
Zозначает, что содержимое bind-монтирования является закрытым и не используется совместно.
Используйте эти параметры с особой осторожностью. Bind-монтирование системного каталога, например /home или /usr, с параметром Z может сделать хост неработоспособным, после чего метки файлов основной системы придётся восстанавливать вручную.
Важно. При использовании bind-монтирований с сервисами метки SELinux (
:Zи:z), а также:roигнорируются. Подробнее см. в moby/moby #32579.
В следующем примере параметр z разрешает нескольким контейнерам совместно использовать содержимое bind-монтирования.
Изменить метку SELinux с помощью параметра --mount невозможно.
$ docker run -d \
-it \
--name devtest \
-v "$(pwd)"/target:/app:z \
nginx:latestDocker Desktop для Mac использует osxfs, чтобы передавать каталоги и файлы из macOS в виртуальную машину Linux. Благодаря этому общие каталоги и файлы становятся доступны Docker-контейнерам, запущенным в Docker Desktop для Mac.
По умолчанию такие общие ресурсы полностью согласованы: при каждой записи на хосте macOS или через монтирование внутри контейнера изменения сбрасываются на диск, поэтому все участники видят одинаковое состояние данных. В некоторых случаях полная согласованность может серьёзно снижать производительность. Начиная с Docker 17.05 согласованность можно настраивать отдельно для каждого монтирования и контейнера. Доступны следующие варианты:
consistentилиdefault— полная согласованность, используемая по умолчанию и описанная выше.delegated— состояние монтирования, которое видит среда выполнения контейнера, считается основным. Изменения из контейнера могут появляться на хосте с задержкой.cached— состояние монтирования, которое видит хост macOS, считается основным. Изменения на хосте могут появляться в контейнере с задержкой.
Во всех операционных системах хоста, кроме macOS, эти параметры полностью игнорируются.
Примеры с --mount и -v дают одинаковый результат.
--mount
$ docker run -d \
-it \
--name devtest \
--mount type=bind,source="$(pwd)"/target,destination=/app,consistency=cached \
nginx:latest-v
$ docker run -d \
-it \
--name devtest \
-v "$(pwd)"/target:/app:cached \
nginx:latest