Bind mounts и относительные пути в Docker Compose
Автор: Казачкин Даниил Михайлович · Обновлено
Для редактирования исходников на компьютере удобно подключить существующую папку внутрь контейнера. Это bind mount: контейнер получает доступ к конкретному пути хоста. После урока вы сможете отличить его от named volume, проверить разрешённый путь и обнаружить ситуацию, когда mount скрыл файлы образа.
Выбор по задаче
В разработке вы меняете HTML в редакторе и сразу читаете его из контейнера: bind mount соответствует этому потоку работы. Для внутренних данных приложения, которыми управляет Docker, удобен named volume. Это выбор владельца пути и способа эксплуатации, а не правило «одно всегда быстрее другого». Docker Desktop добавляет слой обмена между хостом и Linux VM, поэтому результаты Linux нельзя автоматически переносить на Windows.
Bind mount скрывает содержимое каталога назначения в образе. Например, подключение пустой папки к /app прячет ранее собранный app.py. Ошибка «файл не найден» в такой ситуации не доказывает, что COPY при сборке не сработал. Сравните запуск с mount и без него. Механизм bind mount.
Небольшой файловый стенд
Создайте новую папку опыта и запускайте команды из неё. $(pwd) в Bash превращает относительную рабочую директорию в абсолютный путь для Docker CLI.
mkdir -p pages
printf 'bind mount works\n' > pages/index.html
docker run --rm --mount "type=bind,src=$(pwd)/pages,dst=/site,readonly" alpine:3.22 cat /site/index.htmlВы получите строку из файла хоста. Теперь измените файл и повторите чтение: сборка образа не нужна. В отличие от короткого -v, вариант --mount type=bind по умолчанию выдаёт ошибку, если source отсутствует. Это полезнее, чем незаметно получить пустой каталог из-за опечатки.
Путь source относится к машине Docker daemon. Если CLI подключён к удалённому Docker context, локальная папка ноутбука автоматически не отправляется на сервер. Для такого сценария нужен перенос файлов или готовый образ. Проверьте docker context show до диагностики «потерянной» директории.
Относительный путь в Compose
Рядом с папкой pages сохраните compose.yaml:
name: yk-bind-demo
services:
reader:
image: alpine:3.22
command: ["cat", "/site/index.html"]
volumes:
- type: bind
source: ./pages
target: /site
read_only: true
bind:
create_host_path: falseСначала выполните docker compose config, затем docker compose run --rm reader. В итоговой конфигурации проверьте разрешённый абсолютный source. Для локального Compose путь начинается от каталога основного Compose-файла; при объединении нескольких -f база определяется первым файлом. --project-directory может изменить проектную базу. Правила объединения.
Короткая запись ./pages:/site:ro тоже обозначает bind mount. Начальные ./ или ../ позволяют отличить относительный путь от имени named volume. Длинная форма лучше показывает намерение и даёт create_host_path: false: при неверном пути запуск останавливается, а не создаёт пустую папку. В контейнере target остаётся абсолютным путём независимо от source.
Windows, WSL и доступ
Не переносите Bash-подстановку $(pwd) буквально в чужую оболочку. В PowerShell удобно пользоваться Compose с относительным source; проверяйте результат docker compose config. Для Linux-контейнеров Docker Desktop должен видеть выбранный диск/каталог. При разработке из WSL держать исходники в Linux-файловой системе часто удобнее, но окончательное решение проверяйте по производительности своего проекта.
Режим read_only запрещает запись через этот mount, однако не меняет владельца файлов. Если процесс не может даже прочитать документ, смотрите UID/GID, права прохода по каталогам и ограничения ОС. Это отдельная диагностика [прав томов](/lessons/without-university/docker-containerization/docker-developer-18), а не повод включать privileged.
Проверка понимания
Переименуйте pages в pages-old и запустите сервис. Ожидайте ошибку отсутствующего bind source, затем верните путь. Затем в отдельном варианте сравните короткие записи ./pages:/site:ro и pages:/site:ro. Для второй объявите сверху volumes: { pages: {} }: она подключает named volume, а не папку исходников. В длинной форме явное type: bind сохраняет тип подключения независимо от наличия ./. Объясните, почему новый том не содержит ваш HTML. Завершите опыт docker compose down; файлы pages остаются на хосте, поскольку Compose не владеет жизненным циклом bind-каталога.