Зависит от того, какого эффекта вы пытаетесь достичь.
Обратите внимание, что с точки зрения прагматики (то есть того, как на самом деле говорят разработчики), «сброс переменной» может означать две вещи: удаление ее из среды или установка переменной в пустое значение. Технически это две разные операции. На практике, однако, я не сталкивался со случаем, когда программное обеспечение, которым я пытаюсь управлять, различает переменную, отсутствующую в среде, и переменную, присутствующую в среде, но имеющую пустое значение. Я обычно могу использовать любой метод, чтобы получить тот же результат.
Если вам все равно, находится ли переменная в слоях, созданных Docker, но если оставить ее с непустым значением, возникнут проблемы на последующих этапах сборки.
В этом случае вы можете использовать ENV VAR_NAME=
в той точке вашего Dockerfile, из которой вы хотите сбросить переменную. Синтаксическое примечание: Docker допускает два синтаксиса для ENV
: этот ENV VAR=1
совпадает с ENV VAR 1
. Вы можете отделить имя переменной от значения пробелом или знаком равенства. Если вы хотите «сбросить» переменную, установив для нее пустое значение, вы должны использовать синтаксис знака равенства, иначе вы получите ошибку во время сборки.
Так, например, вы можете сделать это:
ENV NOT_SENSITIVE some_value
RUN something
ENV NOT_SENSITIVE=
RUN something_else
Когда something
работает, NOT_SENSITIVE
устанавливается на some_value
. Когда something_else
выполняется, NOT_SENSITIVE
устанавливается в пустую строку.
Важно отметить, что выполнение unset NOT_SENSITIVE
в качестве команды оболочки не будет влиять на что-либо еще, кроме того, что выполняется в этой оболочке. Вот пример:
ENV NOT_SENSITIVE some_value
RUN unset NOT_SENSITIVE && printenv NOT_SENSITIVE || echo "does not exist"
RUN printenv NOT_SENSITIVE
Первый RUN
напечатает does not exist
, потому что NOT_SENSITIVE
сбрасывается при выполнении printenv
и потому что он не установлен printenv
возвращает ненулевой код выхода, который вызывает выполнение echo
. На второй RUN
не влияет unset
в первом RUN
. Он выведет some_value
на экран.
Но что, если мне нужно удалить переменную из среды, а не просто установить ее в пустое значение?
В этом случае использование ENV VAR_NAME=
не будет работать. Я не знаю, как сказать Docker: «С этого момента вы должны удалить эту переменную из среды, а не просто установить для нее пустое значение».
Если вы все еще хотите использовать ENV
для установки вашей переменной, вам придется начинать каждый RUN
, в котором вы хотите, чтобы переменная была сброшена, с unset VAR_NAME
, что приведет к ее сбросу для только для RUN
.
Если вы хотите, чтобы переменная не присутствовала в слоях, созданных Docker.
Предположим, что переменная содержит секрет, и слой может попасть в руки людей, у которых не должно быть секрета. В этом случае вы НЕ МОЖЕТЕ использовать ENV
для установки переменной. Переменная, установленная с ENV
, запекается в слоях, к которым она применяется, и не может быть удалена из этих слоев. В частности (при условии, что переменная имеет имя SENSITIVE
), работает
RUN unset SENSITIVE
не делает ничего , чтобы удалить его из слоя. Приведенная выше команда unset
удаляет только SENSITIVE
из процесса оболочки, который запускается RUN
. Это влияет только на эту оболочку. Это не повлияет на оболочки, порожденные CMD
, ENTRYPOINT
или любой командой, предоставленной при запуске docker run
в командной строке.
Чтобы слои не содержали секрет, я бы использовал docker build --secret=
и RUN --mount=type=secret...
. Например, предполагая, что я сохранил свой секрет в файле с именем sensitive
, у меня может быть RUN
, например:
RUN --mount=type=secret,id=sensitive,target=/root/sensitive \
export SENSITIVE=$(cat /root/sensitive) \
&& [[... do stuff that requires SENSITIVE ]] \
Обратите внимание, что команде, данной RUN
, не обязательно заканчиваться на unset SENSITIVE
. Из-за способа управления процессами и их средами, установка SENSITIVE
в оболочке, порожденной RUN
не имеет никакого эффекта помимо того, что порождает эта оболочка. Изменения среды в этой оболочке не будут влиять на будущие оболочки и не будут влиять на то, что Docker запекает в создаваемые им слои.
Затем сборку можно запустить с помощью:
$ DOCKER_BUILDKIT=1 docker build --secret id=secret,src=path/to/sensitive [...]
Среде для команды docker build
требуется DOCKER_BUILDKIT=1
для использования BuildKit, поскольку этот метод передачи секретов доступен только в том случае, если Docker использует BuildKit для построения образов.