这取决于您要实现的效果。
请注意,从实用角度(即开发人员实际使用时),“取消设置变量”可能有两种含义:从环境中删除它或将变量设置为空值。在技术上,这是两个不同的操作。但在实践中,我并没有遇到过一种情况,即软件区分变量不存在于环境中还是存在于环境中但设置为空值。通常可以使用任一方法获得相同的结果。
如果您不关心变量是否在Docker生成的层中,但将其保留为非空值会导致后续构建步骤出现问题。
对于这种情况,可以在Dockerfile中的任意位置使用ENV VAR_NAME=
来取消变量的设置。语法说明: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
被设置为空字符串。
需要注意的是,作为shell命令 进行 unset NOT_SENSITIVE
不会影响除在该 shell 中执行的内容以外的任何其他内容。以下是一个例子:
ENV NOT_SENSITIVE some_value
RUN unset NOT_SENSITIVE && printenv NOT_SENSITIVE || echo "does not exist"
RUN printenv NOT_SENSITIVE
第一个RUN
会打印does not exist
,因为在printenv
执行时NOT_SENSITIVE
未设置,并且因为它未设置,printenv
返回非零退出码,从而导致执行echo
。第二个RUN
不受第一个RUN
中的unset
影响。它将some_value
打印到屏幕上。
但如果我需要从环境中删除变量,而不仅仅是将其设置为空值怎么办?
在这种情况下,使用ENV VAR_NAME=
是行不通的。我不知道有什么方法告诉Docker“从此时起,您必须从环境中删除此变量,而不仅仅是将其设置为空值”。
如果您仍然想使用ENV
来设置变量,则必须以unset VAR_NAME
开始每个您希望在其中取消设置变量的RUN
,这将仅取消设置该特定的RUN
中的变量。
如果要防止变量存在于Docker生成的层中。
假设该变量包含一个机密信息,而该层可能落入不应拥有该机密的人手中。在这种情况下,您无法使用ENV
来设置变量。使用ENV
设置的变量被嵌入到它适用的层中,并且无法从这些层中删除。特别地,(假设该变量名为SENSITIVE
)运行
RUN unset SENSITIVE
不会从该层中删除它。上面的unset
命令只会从RUN
启动的shell进程中删除SENSITIVE
。它只影响那个shell,不会影响通过CMD
、ENTRYPOINT
或在命令行上运行docker run
提供的任何命令所产生的shell。
为了防止层包含机密信息,我会使用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 ]] \
< p >< em >请注意,< code >RUN 命令执行的指令不需要以 < code >unset SENSITIVE 结束。由于进程及其环境管理方式的原因,通过
RUN
产生的 shell 中设置 < code >SENSITIVE 不会对该 shell 所生成的其他子 shell 或 Docker 创建的层中包含的内容产生影响。
然后可以使用以下命令运行构建:
$ DOCKER_BUILDKIT=1 docker build --secret id=secret,src=path/to/sensitive [...]
docker build
命令的环境需要
DOCKER_BUILDKIT=1
才能使用 BuildKit,因为只有当 Docker 使用 BuildKit 构建镜像时,才能使用此方法传递机密信息。
no_proxy
变量可能更适合您的用例。 - BMitch