如何在dockerfile中取消设置“ ENV”?

时间:2019-04-22 05:10:43

标签: docker dockerfile

由于某些原因,我必须在dockerfile中设置“ http_proxy”和“ https_proxy” ENV。我现在想取消设置它们,因为还有一些构建过程无法通过代理完成。

# dockerfile

# ... some process

ENV http_proxy=http://...
ENV https_proxy=http://...

# ... some process that needs the proxy to finish

UNSET ENV http_proxy # how to I unset the proxy ENV here?
UNSET ENV https_proxy

# ... some process that can't use the proxy 

7 个答案:

答案 0 :(得分:1)

根据docker docs,您需要改用shell命令:

FROM alpine
RUN export ADMIN_USER="mark" \
&& echo $ADMIN_USER > ./mark \
&& unset ADMIN_USER
CMD sh

有关更多详细信息,请参见https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#env

答案 1 :(得分:1)

这取决于您要达到的效果。

请注意,就语用而言(即开发人员的实际说法),“取消设置变量”可能意味着两件事:将其从环境中删除或将变量设置为空值。从技术上讲,这是两个不同的操作。在实践中,虽然我还没有遇到过尝试控制软件区分环境中不存在的变量和环境中存在但设置为空值的变量的情况。我通常可以使用任何一种方法来获得相同的结果。

如果您不关心该变量是否在Docker产生的层中,而将其保留为非空值,则会在以后的构建步骤中引起问题。

在这种情况下,您可以在Dockerfile中要从其取消设置变量的位置使用ENV VAR_NAME=。语法说明:Docker允许ENV使用两种语法:此ENV VAR=1ENV 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作为shell命令不会影响此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,因为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从{{ 1}}开始。它仅影响该外壳。它不会影响RUNCMD或通过在命令行上运行ENTRYPOINT所提供的任何命令生成的shell。

为了防止这些层包含秘密,我将使用docker rundocker 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产生的外壳中的“ |”没有该外壳本身产生的任何影响。此Shell中的环境更改不会影响将来的Shell,也不会影响Docker烘焙到其创建的层中的内容。

然后可以使用以下版本运行构建:

RUN

$ DOCKER_BUILDKIT=1 docker build --secret id=secret,src=path/to/sensitive [...] 命令的环境需要docker build才能使用BuildKit,因为只有在Docker使用BuildKit生成映像的情况下,这种传递秘密的方法才可用。

答案 2 :(得分:1)

您可以在Dockerfile中添加以下行

ENV http_proxy ""
ENV https_proxy ""

答案 3 :(得分:1)

简答

尽量避免不必要的环境变量,所以你不需要取消它们。

如果您必须取消某个命令的设置,您可以执行以下操作:

RUN unset http_proxy https_proxy no_proxy \
    && execute_your_command_here  

如果您必须取消构建图像的设置,您可以执行以下操作:

FROM ubuntu_with_http_proxy

ENV http_proxy= \
    https_proxy= \
    no_proxy=

一旦使用 ENV 指令设置了环境变量,我们就无法真正取消设置它们,因为它很详细:

<块引用>

每个 ENV 行都会创建一个新的中间层,就像 RUN 命令一样。这意味着即使您在未来的层中取消设置环境变量,它仍然会保留在该层中,并且其值可以转储。

见:Best practices for writing Dockerfiles

详情

我更喜欢在构建期间将 http_proxy 定义为参数,如下所示:

FROM ubuntu:20.04

ARG http_proxy=http://host.docker.internal:3128 
ARG https_proxy=http://host.docker.internal:3128 
ARG no_proxy=.your.domain,localhost,127.0.0.1

在公司代理上,我们无论如何都需要身份验证,因此我们需要配置本地代理服务器侦听 127.0.0.1:3128 可以从容器通过 host.docker.internal:3128 访问。这样,如果我们通过 VPN 连接到公司网络(本地/家庭网络被阻止),它也可以在 docker 桌面上运行。

设置 no_proxy 对避免代理服务器泛滥也很重要。

有关 no_proxy 相关主题的更多详细信息,请参阅以下文章:

有时阅读相关文档也不错:

如果我们需要配置这些环境变量,我们可以使用以下命令:

  • 在构建期间 (link):
docker build ... --build-arg http_proxy='http://alternative.proxy:3128/' ...
  • 在运行期间 (link):
docker run ... -env http_proxy='http://alternative.proxy:3128/' ...

答案 4 :(得分:0)

AFAIK,Dockerfile中没有本机支持此功能的语句。但是,您也许可以使用普通的shell命令将其取消设置-

OPENSSL_CONF

答案 5 :(得分:0)

如果在映像构建过程中需要env var,但不应保留它们,只需清除它们即可。在下面的示例中,正在运行的容器显示空的环境变量。

Dockerfile

# set proxy
ARG http_proxy
ARG https_proxy
ARG no_proxy
ENV http_proxy=$http_proxy
ENV https_proxy=$http_proxy
ENV no_proxy=$no_proxy

# ... do stuff that needs the proxy during the build, like apt-get, curl, et al.

# unset proxy
ENV http_proxy=
ENV https_proxy=
ENV no_proxy=

build.sh

docker build -t the-image \
    --build-arg http_proxy="$http_proxy" \
    --build-arg https_proxy="$http_proxy" \
    --build-arg no_proxy="$no_proxy" \
    --no-cache \
    .

run.sh

docker run --rm -i \
    the-image \
    sh << COMMANDS
        env
COMMANDS

输出

no_proxy=
https_proxy=
http_proxy=
...

答案 6 :(得分:0)

我发现秘密方法行不通,因为当我在交互模式下运行环境变量时,我需要将env变量保留在容器中,但随后需要完全删除该变量,以便稍后进行生产。

在开发阶段进行的工作是,我将环境变量附加到/root/.basrc文件中

RUN echo export AWS_PROFILE=role-name >> /root/.bashrc
``

In the production stage of the build I then removed the last line of /root/.bashrc:

RUN sed -i'$ d'/root/.bashrc