【问题标题】:How to unset "ENV" in dockerfile?如何在 dockerfile 中取消设置“ENV”?
【发布时间】:2019-04-22 05:10:42
【问题描述】:

出于某些原因,我必须在我的 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 

【问题讨论】:

  • 这只是针对特定的主机名吗?有一个 no_proxy 变量可能更适合您的用例。
  • 有一个 no_proxy 变量可以工作,但它不是标准化的,你可能会在不同的应用程序上得到不同的结果。见:link

标签: docker dockerfile


【解决方案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_SENSITIVEprintenv 执行时未设置,并且因为它未设置printenv 返回一个非零退出代码,导致echo 执行。第二个RUN 不受第一个RUN 中的unset 的影响。它将在屏幕上打印some_value

但是如果我需要从环境中移除变量,而不仅仅是将其设置为空值呢?

在这种情况下使用ENV VAR_NAME= 将不起作用。我不知道有什么方法可以告诉 Docker“从现在开始,你必须从环境中删除这个变量,而不仅仅是将它设置为空值”。

如果您仍想使用ENV 来设置变量,那么您必须在每个RUN 开始,您希望在其中使用unset VAR_NAME 取消设置变量,这将为 取消设置 仅限于RUN

如果要防止变量出现在 Docker 生成的层中。

假设该变量包含一个秘密,并且该层可能落入不应该拥有该秘密的人手中。在这种情况下,您不能使用ENV 来设置变量。带有ENV 的变量集被烘焙到它应用的层中,并且不能从这些层中删除。特别是(假设变量名为SENSITIVE)正在运行

RUN unset SENSITIVE

不做任何事情将其从层中删除。上面的unset 命令仅从RUN 启动的shell 进程中删除SENSITIVE。它只影响那个外壳。它不会影响由CMDENTRYPOINT 或通过在命令行运行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 ]] \

请注意,给RUN 的命令不需要以unset SENSITIVE 结尾。 由于进程及其环境的管理方式,在@ 生成的shell 中设置SENSITIVE 987654366@ 除了外壳本身产生的效果外,没有任何影响。此 shell 中的环境更改不会影响未来的 shell,也不会影响 Docker 在其创建的层中烘焙的内容。

然后构建可以运行:

$ DOCKER_BUILDKIT=1 docker build --secret id=secret,src=path/to/sensitive [...]

docker build 命令的环境需要DOCKER_BUILDKIT=1 才能使用 BuildKit,因为这种传递秘密的方法只有在 Docker 使用 BuildKit 构建镜像时才可用。

【讨论】:

    【解决方案2】:

    如果在映像构建过程中需要环境变量,但它们不应该持续存在,只需清除它们。在以下示例中,正在运行的容器显示空环境变量。

    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 \
        .
    

    运行.sh

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

    输出

    no_proxy=
    https_proxy=
    http_proxy=
    ...
    

    【讨论】:

    • 这会在中间层暴露环境吗?
    • 这不起作用(在 debian 9 上测试)。 no_proxy 是由 ~/.docker/config.json 中的 docker 设置设置的值。即使您写“ENV no_proxy=".,这也是将出现在图像中的值
    • 这也不适用于 node.js 进程——node.js 似乎对空的 http[s]_proxy env vars 很不满意 :(
    • 我们真的不需要 ENV 行。我们可以简单地使用ARG http_proxy="http://host.docker.internal:3128/" 或任何您的代理。
    • 如果我们传入构建参数以便通过覆盖它们从容器中删除它们,我们是否不需要 ENV 行?硬编码的构建参数存储在历史记录中,不是吗?
    【解决方案3】:

    简答

    尽量避免不必要的环境变量,这样就不需要取消设置了。

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

    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/' ...
    

    另外请注意,我们甚至不需要定义与代理相关的参数,因为这些参数已经根据以下部分进行了预定义:

    Dockerfile reference - Predefined ARGs

    【讨论】:

      【解决方案4】:

      您可以在 Dockerfile 中添加以下行

      ENV http_proxy ""
      ENV https_proxy ""
      

      【讨论】:

        【解决方案5】:

        根据 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

        【讨论】:

        • > 每个 ENV 行都会创建一个新的中间层,就像 RUN 命令一样。这意味着即使您在将来的层中取消设置环境变量,它仍然会保留在该层中,并且可以转储其值。您可以通过创建如下所示的 Dockerfile 进行测试,然后构建它。
        【解决方案6】:

        我发现秘密方法不起作用,因为当我在交互模式下运行 env 变量时,我需要将 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:
        

        运行 sed -i '$ d' /root/.bashrc

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-12-15
          • 1970-01-01
          • 2014-07-15
          • 1970-01-01
          • 2016-04-26
          • 1970-01-01
          • 2019-07-06
          • 1970-01-01
          相关资源
          最近更新 更多