Добавьте том в Docker, но исключите подпапку

211

Предположим, у меня есть контейнер Docker и папка на моем хосте /hostFolder. Теперь , если я хочу , чтобы добавить эту папку в контейнер Докер как объем, то я могу сделать это либо с использованием ADDв Dockerfileили установки его в качестве тома.

Все идет нормально.

Теперь /hostFolderсодержит подпапку /hostFolder/subFolder.

Я хочу смонтировать /hostFolderв контейнер Docker (независимо от того, имеет ли значение чтение-запись или только для чтения, для меня это работает), но я НЕ хочу, чтобы он был включен /hostFolder/subFolder. Я хочу исключить это, и я также хочу, чтобы Docker-контейнер мог вносить изменения в эту подпапку, без последствий того, чтобы она также изменялась на хосте.

Это возможно? Если да, то как?

Голо Роден
источник
2
@AbhijitSarkar это не очень конструктивный (и ни в коем случае не полезный) комментарий.
Кано
1
@ Kano Это комментарий, а не ответ.
Абхиджит Саркар

Ответы:

400

Используя docker-compose, я могу использовать node_modules локально, но игнорировать его в контейнере docker, используя следующий синтаксис в docker-compose.yml

volumes:
   - './angularApp:/opt/app'
   - /opt/app/node_modules/

Таким образом, все в ./angularAppсопоставлено, /opt/appа затем я создаю другой том для монтирования, /opt/app/node_modules/который теперь является пустым каталогом - даже если на моем локальном компьютере ./angularApp/node_modulesне пусто.

kernix
источник
3
Это работает, но я не могу удалить эти каталоги внутри контейнера. Например: мне нужно заменить /opt/app/node_modules/другой каталог с тем же именем. Произошла ошибка: «Громкость занята»
Степан Юдин
32
Не забудьте про косую черту! например. / opt / app / node_modules не работает, он будет перезаписан ./angularApp/node_modules
Stingus
3
Этот трюк работал для меня, но больше не кажется, даже для самого файла Compose. Любопытно, если это также перестало работать на других.
plinehan
8
Спасибо! Вы спасли мой день! В случае использования простого докера, а не композитов, это выглядело бы так: -v $(pwd):/build/ -v /build/node_modules
Богдан Март
3
Я нашел документ, docs.docker.com/storage/volumes/… . If you start a container which creates a new volume, as above, and the container has files or directories in the directory to be mounted (such as /app/ above), the directory’s contents are copied into the volume.
Хироши
119

Если вы хотите, чтобы подкаталоги игнорировались docker-compose, но были постоянными, вы можете сделать следующее docker-compose.yml:

volumes:
  node_modules:
services:
  server:
    volumes:
      - .:/app
      - node_modules:/app/node_modules

Это смонтирует ваш текущий каталог как общий том, но смонтирует постоянный том докера вместо вашего локального node_modulesкаталога. Это похоже на ответ @kernix, но это позволит node_modulesсохраняться между docker-compose upзапусками, что, вероятно, является желаемым поведением.

Нейт Т
источник
20
Названные тома - превосходный подход. Подсказка: убедитесь, что вы не используете дефинированное имя тома. Вы проведете небольшую часть своей жизни в отладочном кошмаре, только чтобы узнать, что вас снова одурачил нелепый нюанс.
dustintheweb
3
«Обратите внимание, что docker-compose down уничтожит эти постоянные тома». Это не так в Docker для Mac v 17.0.5+ (и, возможно, более старых версиях). docker-compose downудалит контейнеры, но объем будет сохраняться, пока вы не запустите что-то вродеdocker system prune
BrDaHa
3
Если кому-то интересно понять, почему использование node_modules:именованного тома «игнорирует» /app/node_modulesв контейнере докера, может оказаться полезным это сообщение Как докер обрабатывает несколько типов монтирования?
ира
3
Я не знаю, делаю ли я что-то не так, но если я сделаю это, запустите контейнер, а затем запустите npm install на машине HOST, это также изменит node_modules внутри CONTAINER. Я не могу представить, почему кто-то хотел бы сделать это, но все же я ищу более чистое разделение.
Ренра
3
У @Renra была точно такая же проблема, мой хост-компьютер постоянно записывал поверх node_modules, даже если у меня был названный том ... вызывал всевозможные проблемы несовместимости. Бросил на ее исправление и работал вокруг него только копируя мою папку Src вместо целого репо
dancypants
19

Чтобы исключить файл, используйте следующее

volumes:
   - /hostFolder:/folder
   - /dev/null:/folder/fileToBeExcluded
Фрэнк Вонг
источник
6
Идеальное решение для того, что мне нужно (чтобы НЕ отображать node_modules на хост, потому что символические ссылки сломались на хосте Windows). Указание на / dev / null не сработало, но создание пустого каталога и его сопоставление с ним работало отлично и решало проблемы, с которыми я столкнулся - спасибо за эту идею.
Лиам Хаммет
1
Это не работает в Docker для Mac 18.09.0: Cannot start service xxx: OCI runtime create failed: container_linux.go:348: starting container process caused "process_linux.go:402: container init caused \"rootfs_linux.go:58: mounting \\\"/dev/null\\\" to rootfs \\\"/var/lib/docker/overlay2/d15ed56ad020d408c63a1f6a6365dbb88d5d3b78a4605980d3faa9861102ef21/merged\\\" at [...] unknown: Are you trying to mount a directory onto a file (or vice-versa)? Check if the specified host path exists and is the expected type. Добавление косой черты не помогло.
Блейз
Я могу подтвердить, что он не работает ни на Ubuntu 16.04 с Docker 18.09.3.
Дирк
Это не работает для меня. Все, что он делает, это копирует /dev/nullв контейнер, как файл устройства.
Радон Росборо
1
Обратите внимание, что это работает только для исключения файлов! / DEV / нуль является файлом , и так должен быть целью, сообщение об ошибке совершенно ясно об этом: Are you trying to mount a directory onto a file (or vice-versa)? Check if the specified host path exists and is the expected type. Это не совсем то, что ищет OP, но это было очень полезно для меня, так как мне нужно было исключить один файл.
Avius
13

Во-первых, использование ADDинструкции в Dockerfile очень отличается от использования тома (либо через -vаргумент to, docker runлибо через VOLUMEинструкцию в Dockerfile). ADDИ COPYкоманда просто взять копию файлов в то время docker buildзапускаются. Эти файлы не обновляются до тех пор, пока с помощью docker buildкоманды не будет создан новый образ . В отличие от этого, использование тома означает, что «этот каталог не должен храниться в образе контейнера; вместо этого используйте каталог на хосте»; всякий раз, когда файл внутри тома изменяется, хост и контейнер увидят его немедленно.

Я не верю, что вы можете достичь того, чего хотите, используя тома, вам придется переосмыслить структуру каталогов, если вы хотите это сделать.

Тем не менее, это довольно просто добиться использования COPY(что должно быть предпочтительнее ADD). Вы можете использовать .dockerignoreфайл, чтобы исключить подкаталог, или вы можетеCOPY все файлы затем сделатьRUN rm bla чтобы удалить подкаталог.

Помните, что любые файлы, которые вы добавляете в образ с COPYили ADDдолжны быть в контексте сборки, то есть в или под каталогом, из которого вы запускаете docker build.

Адриан Муат
источник
1
узнавать что-то новое каждый день :-) COPY и ADD работают из контекста сборки (не хоста). Можно ли использовать том для маскировки подпапки? ОП хочет смонтировать / hostFolder (я думаю) и отключить / hostFolder / subFolder. Если бы для каждого был VOLUME, но был «смонтирован» только-hostFolder (-v), изолировал бы это изменение subFolder в контейнере?
Грег
Я не уверен, я никогда не пробовал вложения томов. Я не уверен, что это хорошая идея, но я должен рассмотреть ее.
Адриан Муат
1
Кажется, я нигде не могу найти пример того, что поместить в .dockerignoreфайл, чтобы исключить подкаталог (или даже каталог). Учитывая, что это заявленная цель файла, это довольно странно.
Лукас Оберхубер
1
как только вы добавляете какие-либо файлы, они все равно оказываются в некоторых слоях. Поэтому удаление их не поможет вам скрыть их, если они чувствительны к безопасности, или уменьшить размер изображения (потому что они будут в нижележащих слоях). Есть варианты для squashслоев. Один из них - github.com/goldmann/docker-squash, а другой - oc ex dockerbuildиз проекта openshift.
Акостадинов
6

Похоже, старое решение больше не работает (по крайней мере, для меня). Хотя создание пустой папки и сопоставление целевой папки с ней помогло.

volumes:
   - ./angularApp:/opt/app
   - .empty:/opt/app/node_modules/
holdbar
источник
У меня тоже не работает, с docker-compose 1.25.0-rc3синтаксисом файла v3.
thisismydesign
6

С помощью командной строки Docker:

docker run \
    --mount type=bind,src=/hostFolder,dst=/containerFolder \
    --mount type=volume,dst=/containerFolder/subFolder \
    ...other-args...

-vОпция также может быть использована (кредит Богданом Mart ), но --mountяснее и рекомендуются .

DS.
источник
6

для людей, у которых также была проблема, что папка node_modules все еще перезаписывает из вашей локальной системы и наоборот

volumes:
  node_modules:
services:
  server:
    volumes:
      - .:/app
      - node_modules:/app/node_modules/

Это решение, с /последним следом после node_modules.

Daenor
источник
0

Чтобы исключить смонтированный файл, содержащийся в томе вашей машины, вам придется перезаписать его, выделив том же файлу. В вашем конфигурационном файле:

services:
  server:
    build : ./Dockerfile
    volumes:
      - .:/app

Пример в вашем dockerfile:

# Image Location
FROM node:13.12.0-buster
VOLUME /app/you_overwrite_file
Эммарио Делар
источник