Dockerfile - установить ENV как результат команды

90

Можно ли установить переменную ENV для докеров в результате выполнения команды? Подобно:

ENV MY_VAR whoami

я хочу, чтобы MY_VAR получил значение "root" или что-то еще, что возвращает whoami

Султанен
источник

Ответы:

23

Как дополнение к DarkSideF ответ.

Вы должны знать, что каждая строка / команда в Dockerfile запускается в другом контейнере.

Вы можете сделать что-то вроде этого:

RUN export bleah=$(hostname -f);echo $bleah;

Это выполняется в одном контейнере.

Димитрие Митителу
источник
14
Просто чтобы прояснить - $bleahэто не доступны в любом месте за пределами этой команды RUN, даже не на следующей строке в том же dockerfile, не говоря уже о другом изображении он основан прочь. Здесь действительно очевидная отсутствующая функция в докере, похоже, что запись и чтение из файла - это единственный способ на самом деле хранить (динамические) переменные в изображениях и передавать их между изображениями, что кажется супер хакерским.
davnicwil
17

У меня была такая же проблема, и я нашел способ установить переменную среды как результат функции с помощью команды RUN в файле dockerfile.

Например, мне нужно установить SECRET_KEY_BASE для приложения Rails только один раз, не меняя, как при запуске:

docker run  -e SECRET_KEY_BASE="$(openssl rand -hex 64)"

Вместо этого я пишу в строку Dockerfile, например:

RUN bash -l -c 'echo export SECRET_KEY_BASE="$(openssl rand -hex 64)" >> /etc/bash.bashrc'

и моя переменная env доступна из root, даже после входа в bash. или, может быть

RUN /bin/bash -l -c 'echo export SECRET_KEY_BASE="$(openssl rand -hex 64)" > /etc/profile.d/docker_init.sh'

тогда это переменная, доступная в командах CMD и ENTRYPOINT

Docker кеширует его как слой и изменяет только если вы измените некоторые строки перед ним.

Вы также можете попробовать разные способы установки переменной окружения.

DarkSideF
источник
/Etc/profile.d/docker_init.sh все еще актуален? Этот ответ - единственное упоминание об этом, которое я могу найти в Google, и он не работает для меня. Возможно, это было частью механизма выполнения Docker в 2016 году, который больше не актуален?
SigmaX
1
@SigmaX Это не докер, это скорее Linux . Любой *.shфайл внутри /etc/profile.d/используется для заполнения среды
Madacol
7

Этот ответ является ответом на @DarkSideF ,

Предлагаемый им метод заключается в следующем Dockerfile:

RUN bash -l -c 'echo export SECRET_KEY_BASE="$(openssl rand -hex 64)" >> /etc/bash.bashrc'

( добавление экспорта в/etc/bash.bashrc )

Это хорошо, но переменная среды будет доступна только для процесса /bin/bash, и если вы попытаетесь запустить приложение докера, например приложение Node.js, оно /etc/bash.bashrcбудет полностью проигнорировано, и ваше приложение не будет иметь ни единой подсказки, что SECRET_KEY_BASEпроисходит при попытке для доступа process.env.SECRET_KEY_BASE.

Вот почему ENVключевое слово - это то, что все пытаются использовать с динамической командой, потому что каждый раз, когда вы запускаете свой контейнер или используете execкоманду, Docker будет проверять ENVи передавать каждое значение в текущем процессе (аналогично -e).

Одно из решений - использовать оболочку (кредит @duglin в этом выпуске на github ). Имейте файл-оболочку (например envwrapper) в корне вашего проекта, содержащий:

#!/bin/bash
export SECRET_KEY_BASE="$(openssl rand -hex 64)"
export ANOTHER_ENV "hello world"
$*

а затем в вашем Dockerfile:

...
COPY . .
RUN mv envwrapper /bin/.
RUN chmod 755 /bin/envwrapper
CMD envwrapper myapp
vdegenne
источник
2

В дополнение к ответу @ DarkSideF, если вы хотите повторно использовать результат предыдущей команды в своем Dockerfile во время процесса сборки , вы можете использовать следующий обходной путь:

  1. запустить команду, сохранить результат в файл
  2. используйте подстановку команд, чтобы получить предыдущий результат из этого файла в другую команду

Например :

RUN echo "bla" > ./result
RUN echo $(cat ./result)

Для чего-то более чистого вы также можете использовать следующую суть, которая предоставляет небольшой CLI с именем envstore.py:

RUN envstore.py set MY_VAR bla
RUN echo $(envstore.py get MY_VAR)

Или вы можете использовать библиотеку python-dotenv с аналогичным интерфейсом командной строки.

sebpiq
источник
2

Не уверен, что это то, что вы искали, но для внедрения переменных ENV или ARGS в вашу сборку .Dockerfile этот шаблон работает.

в вашем my_build.sh:

echo getting version of osbase image to build from
OSBASE=$(grep "osbase_version" .version | sed 's/^.*: //')

echo building docker
docker build -f \
--build-arg ARTIFACT_TAG=$OSBASE \
PATH_TO_MY.Dockerfile \
-t my_artifact_home_url/bucketname:$TAG .

для получения ARG в вашем .Dockerfile фрагмент может выглядеть так:

FROM scratch
ARG ARTIFACT_TAG
FROM my_artifact_home_url/bucketname:${ARTIFACT_TAG}

в качестве альтернативы для получения ENV в вашем .Dockerfile фрагмент может выглядеть так:

FROM someimage:latest
ARG ARTIFACT_TAG
ENV ARTIFACT_TAG=${ARTIFACT_TAG}

идея заключается в том, что вы запускаете сценарий оболочки, который вызывает файл .Dockerfile с аргументами, переданными в качестве параметров сборки.

Кат
источник