Как включить файлы вне контекста сборки 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 ..

Ответ 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