Получить значение переменной среды в Dockerfile

254

Я создаю контейнер для приложения ruby. Конфигурация моего приложения содержится в переменных окружения (загружается в приложение с помощью dotenv ).

Одной из этих переменных конфигурации является общедоступный IP-адрес приложения, который используется внутри системы для создания ссылок. Мне нужно добавить запись dnsmasq, указывающую этот ip на 127.0.0.1 внутри контейнера, чтобы он мог получать ссылки приложения, как если бы он не был в контейнере.

Поэтому я пытаюсь установить ENVв моем Dockerfile, который будет передавать переменную среды в контейнер.

Я попробовал несколько вещей.

ENV REQUEST_DOMAIN $REQUEST_DOMAIN
ENV REQUEST_DOMAIN `REQUEST_DOMAIN`

Все передает строку «REQUEST_DOMAIN» вместо значения переменной окружения. Есть ли способ передать значения переменных среды с хост-машины в контейнер?

Дэмиен Мэтью
источник

Ответы:

392

Вы должны использовать ARGдирективу в вашем Dockerfile, которая предназначена для этой цели.

ARGИнструкция определяет переменную , что пользователи могут проходить при построении времени строителя с командой докер сборки , используя --build-arg <varname>=<value>флаг.

Таким образом, ваш Dockerfile будет иметь следующую строку:

ARG request_domain

или если вы предпочитаете значение по умолчанию:

ARG request_domain=127.0.0.1

Теперь вы можете ссылаться на эту переменную внутри вашего Dockerfile:

ENV request_domain=$request_domain

тогда вы создадите свой контейнер следующим образом:

$ docker build --build-arg request_domain=mydomain Dockerfile


Примечание 1. Ваш образ не будет создан, если вы указали ссылку ARGв своем Dockerfile, но исключили его в --build-arg.

Примечание 2. Если пользователь указывает аргумент сборки, который не был определен в файле Docker, сборка выводит предупреждение:

[Предупреждение] Один или несколько сборочных аргументов [foo] не использовались.

Дэниел ван Флаймен
источник
12
ARG доступен начиная с версии докера v1.9.
Synesso
Это поддерживается для удаленного построения на Docker репо?
Джеймс Лин
4
Your image will not build if you have referenced an ARG in your Dockerfile but excluded it in --build-argты неправ. Вы можете создать изображение со ссылками даже без --build-arg. Кроме того, вы можете установить значение по умолчанию для сборки аргумента.
ALex_hha
1
Какова цель линии ENV? Для меня --build-arg + ARG было достаточно.
Фил
3
ARG определяет переменную, которая будет использоваться внутри файла dockerfile в последующих командах. ENV определяет переменную среды, которая передается в контейнер.
гермафродит
56

Так что вы можете сделать: cat Dockerfile | envsubst | docker build -t my-target -

Затем создайте Dockerfile с чем-то вроде:

ENV MY_ENV_VAR $MY_ENV_VAR

Я предполагаю, что могут быть проблемы с некоторыми специальными символами, но это работает, по крайней мере, в большинстве случаев.

jonasfj
источник
13
Это не работает, если вам нужно ДОБАВИТЬ файлы из каталога, содержащего Dockerfile.
Том Хеннен
2
Очень хорошее решение! На Mac вы можете получить envsubstкак часть brew install gettext. Но из-за возможных конфликтов с системой сборки BSD она «только для бочонка» и никаких сообщений не производится. Тем не менее, это безопасно сделать, ln -s /usr/local/Cellar/gettext/*/bin/envsubst /usr/local/bin/чтобы добавить эту одну команду в ваш путь. (Это действительно либсы, которые вызывают беспокойство.) Или вы можете использовать его в своем /usr/local/Cellar/gettext/*/bin/envsubstместе
Бруно Броноски
1
Чтобы пояснить комментарий @ TomHennen, конвейерная передача Dockerfile docker build -, в частности, не работает, когда вы ссылаетесь на относительные пути из вашего Dockerfile, независимо от подстановки env var.
superEb
4
Re @ комментарий TomHennen, в, если вы действительно хотите использовать контекстно-зависимые команды , как COPY в вашем Dockerfile вы всегда можете перенаправить вывод envsubst во временный файл , а затем кормить , что в docker buildвместо этого. Пример: cat Dockerfile | envsubst > DockerfileWithEnvVarsтогда docker build -t my-target -f DockerfileWithEnvVars ., тогдаrm DockerfileWithEnvVars
snark
Или вы можете использовать губку из пакета envsubst < Dockerfile | sponge Dockerfile
moreutils
19

Альтернативное использование envsubstбез потери возможности использовать такие команды, как COPYили ADD, и без использования промежуточных файлов будет состоять в использовании Bash's Process Substitution :

docker build -f <(envsubst < Dockerfile) -t my-target .
Л. Альберто Хименес
источник
3
к сожалению, это, кажется, не работает (Docker 17.09), я получаю ошибкуunable to prepare context: the Dockerfile (/dev/fd/63) must be within the build context
Александр Klimetschek
11

Загрузка переменных среды из файла, который вы создаете во время выполнения.

export MYVAR="my_var_outside"
cat > build/env.sh <<EOF
MYVAR=${MYVAR}
EOF

... тогда в Dockerfile

ADD build /build
RUN /build/test.sh

где test.sh загружает MYVAR из env.sh

#!/bin/bash
. /build/env.sh
echo $MYVAR > /tmp/testfile
Дэн С
источник
4

Если вы просто хотите найти и заменить все переменные окружения ($ ExampleEnvVar) в Dockerfile, то скомпилируйте его так:

envsubst < /path/to/Dockerfile | docker build -t myDockerImage . -f -

snassr
источник
Лучший ответ здесь, и, основываясь на этом, смог сделать: envsubst < ./Dockerfile | docker build -squash -t ${DOCKIMG}:${VERSION} . -f -где FROMстрока использует переменную окружения.
mikequentel
-6

добавить -eключ для передачи переменных среды в контейнер. пример:

$ MYSQLHOSTIP=$(sudo docker inspect -format="{{ .NetworkSettings.IPAddress }}" $MYSQL_CONRAINER_ID)
$ sudo docker run -e DBIP=$MYSQLHOSTIP -i -t myimage /bin/bash

root@87f235949a13:/# echo $DBIP
172.17.0.2
Валентин Кантор
источник
6
Дэмиен хочет создать образ. -e вместо этого работает с командой run.
Андрес Рестрепо