Как включить файлы вне контекста сборки Docker?
Как включить файлы из контекста сборки Docker с помощью команды "ADD" в файле Docker?
Из документации Docker:
Путь должен быть внутри контекста сборки; Вы не можете ДОБАВИТЬ.. /something/something, потому что первый шаг сборки докера - это отправить каталог контекста (и подкаталоги) демону докера.
Я не хочу реструктурировать весь свой проект, чтобы приспособить Docker к этому вопросу. Я хочу сохранить все мои файлы Docker в одном подкаталоге.
Кроме того, похоже, что Docker еще не поддерживает (и может не поддерживать) символические ссылки: команда Dockerfile ADD не следует по символическим ссылкам на хосте # 1676.
Единственное, о чем я могу подумать, это включить шаг перед сборкой, чтобы скопировать файлы в контекст сборки Docker (и настроить мой контроль версий для игнорирования этих файлов). Есть ли лучший обходной путь для этого?
Ответы
Ответ 1
Лучший способ обойти это - указать Dockerfile независимо от контекста сборки, используя -f.
Например, эта команда предоставит команде ADD доступ ко всему в вашем текущем каталоге.
docker build -f docker-files/Dockerfile .
Обновление: Docker теперь позволяет иметь Dockerfile вне контекста сборки (исправлено в 18.03.0-ce, https://github.com/docker/cli/pull/886). Так что вы также можете сделать что-то вроде
docker build -f ../Dockerfile .
Ответ 2
В Linux вы можете монтировать другие каталоги вместо символической ссылки
mount --bind olddir newdir
Подробнее см. https://superuser.com/questions/842642.
Я не знаю, доступно ли что-то подобное для других ОС.
Я также попытался использовать Samba для совместного доступа к папке и ее повторного подключения к контексту Докера, который также работал.
Ответ 3
Я часто использую --build-arg
для этой цели. Например, после добавления следующего в Dockerfile:
ARG SSH_KEY
RUN echo "$SSH_KEY" > /root/.ssh/id_rsa
Вы можете просто сделать:
docker build -t some-app --build-arg SSH_KEY="$(cat ~/file/outside/build/context/id_rsa)" .
Но обратите внимание на следующее предупреждение из документации Docker:
Предупреждение: не рекомендуется использовать переменные времени сборки для передачи таких секретов, как ключи github, учетные данные пользователя и т.д. Значения переменных времени сборки видны любому пользователю образа с помощью команды истории докера.
Ответ 4
Если вы прочитали обсуждение в проблема 2745, не только докер может никогда не поддерживать символические ссылки, они могут никогда не поддерживать добавление файлов вне вашего контекста. Кажется, это философия дизайна, что файлы, которые входят в сборку докеров, должны явно быть частью его контекста или быть из URL-адреса, где он предположительно развернут также с фиксированной версией, чтобы сборка повторялась с хорошо известными URL-адресами или файлами, докерный контейнер.
Я предпочитаю строить из контролируемого версией источника - т.е. сборка докеров -t stuff http://my.git.org/repo - в противном случае я создаю из случайного места со случайными файлами.
принципиально, нет.... - SvenDowideit, Docker Inc
Просто мое мнение, но я думаю, вы должны реструктурировать, чтобы разделить хранилища кода и докеров. Таким образом, контейнеры могут быть универсальными и вытягивать любую версию кода во время выполнения, а не время сборки.
В качестве альтернативы используйте докеры в качестве основного артефакта развертывания кода, а затем вы помещаете файл докеров в корневой каталог репозитория кода. если вы идете по этому маршруту, вероятно, имеет смысл иметь родительский контейнер докеров для более общих сведений о системном уровне и дочерний контейнер для настройки, специфичной для вашего кода.
Ответ 5
Я потратил много времени, пытаясь выяснить хороший шаблон и как лучше объяснить, что происходит с поддержкой этой функции. Я понял, что лучший способ объяснить это было следующим...
- Dockerfile: будет видеть файлы только по своему относительному пути
- Контекст: место в "пространстве", куда будут скопированы файлы, которыми вы хотите поделиться, и ваш Dockerfile
Итак, с учетом вышесказанного, вот пример Dockerfile, который должен повторно использовать файл с именем start.sh
Dockerfile
Он ALWAYS
будет загружаться со своего относительного пути, имея текущий каталог dir в качестве local
ссылки на указанные вами пути.
COPY start.sh /runtime/start.sh
файлы
Учитывая эту идею, мы можем подумать о том, чтобы иметь несколько копий для файлов Docker, создающих определенные вещи, но им всем нужен доступ к start.sh
.
./all-services/
/start.sh
/service-X/Dockerfile
/service-Y/Dockerfile
/service-Z/Dockerfile
./docker-compose.yaml
Учитывая эту структуру и файлы выше, здесь docker-compose.yml
докер-compose.yaml
- В этом примере ваш
shared
контекстный каталог является runtime
. - Та же ментальная модель здесь, думайте, что все файлы в этом каталоге перемещены в так называемый
context
. - Точно так же просто укажите Dockerfile, который вы хотите скопировать в тот же каталог. Вы можете указать это, используя
dockerfile
.
- каталог, в котором находится ваш основной контент, является фактическим контекстом, который нужно установить.
docker-compose.yml
выглядит следующим образом
version: "3.3"
services:
service-A
build:
context: ./all-service
dockerfile: ./service-A/Dockerfile
service-B
build:
context: ./all-service
dockerfile: ./service-B/Dockerfile
service-C
build:
context: ./all-service
dockerfile: ./service-C/Dockerfile
-
all-service
устанавливается в качестве контекста, туда копируется общий файл start.sh
, а также Dockerfile, указанный каждым dockerfile
. - Каждый будет построен по-своему, поделившись стартовым файлом!
Ура!
Ответ 6
Я считаю, что более простым способом было бы изменить сам контекст.
Так, например, вместо того, чтобы давать:
docker build -t hello-demo-app .
который устанавливает текущий каталог как контекст, скажем, вы хотели, чтобы родительский каталог был контекстом, просто используйте:
docker build -t hello-demo-app ..
Ответ 7
Вы также можете создать tarball того, что нужно для первого изображения, и использовать его в качестве своего контекста.
https://docs.docker.com/engine/reference/commandline/build/#/tarball-contexts
Ответ 8
У меня была такая же проблема с проектом и некоторыми файлами данных, которые я не смог переместить в контекст репо по причинам HIPPA. В итоге я использовал 2 Dockerfiles. Один создает главное приложение без необходимых мне материалов вне контейнера и публикует их во внутреннем репо. Затем второй файл Docker извлекает это изображение, добавляет данные и создает новое изображение, которое затем развертывается и никогда нигде не сохраняется. Не идеально, но это помогло мне сохранить конфиденциальную информацию в хранилище.
Ответ 9
Используя docker-compose, я сделал это, создав службу, которая монтирует нужные мне тома и фиксируя образ контейнера. Затем в последующем сервисе я полагаюсь на ранее зафиксированный образ, в котором все данные хранятся в смонтированных местах. Затем вам придется скопировать эти файлы в их конечное место назначения, так как смонтированные на хосте каталоги не фиксируются при выполнении команды docker commit
Вам не нужно использовать docker-compose для этого, но это немного облегчает жизнь
# docker-compose.yml
version: '3'
services:
stage:
image: alpine
volumes:
- /host/machine/path:/tmp/container/path
command: bash -c "cp -r /tmp/container/path /final/container/path"
setup:
image: stage
# setup.sh
# Start "stage" service
docker-compose up stage
# Commit changes to an image named "stage"
docker commit $(docker-compose ps -q stage) stage
# Start setup service off of stage image
docker-compose up setup