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

nnvyjq4y  于 2023-01-04  发布在  Docker
关注(0)|答案(6)|浏览(545)

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

vom3gejh1#

这取决于你想达到什么样的效果。
请注意,作为一个语用问题(即开发人员实际上是如何说话的),“取消设置变量”可能意味着两件事:将变量从环境中删除,或者将变量设置为空值。从技术上讲,这是两种不同的操作。但实际上,我还没有遇到过这样的情况:我试图控制的软件区分变量不存在于环境中,以及变量存在于环境中但被设置为空值。我通常可以使用这两种方法中的任何一种来获得相同的结果。

如果您不关心该变量是否位于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,因为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。它不会影响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结尾。* 由于进程及其环境的管理方式,在由RUN派生的shell中设置SENSITIVE不会产生任何超出shell本身派生的效果。此shell中的环境更改不会't影响未来的壳,也不会影响什么多克烘烤到层,它创建。

然后可以使用以下命令运行构建:

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

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

368yc8dk

368yc8dk2#

如果在映像构建过程中需要env变量,但它们不应该持续存在,只需清除它们。在下面的示例中,运行的容器显示空的env变量。
停靠文件

# 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=
...
6rqinv9w

6rqinv9w3#

根据Docker文档,您需要使用shell命令:

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

See https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#env for more details.

3phpmpom

3phpmpom4#

简短答案

尽量避免不必要的环境变量,这样就不需要取消设置它们。
如果必须取消设置某个命令,可执行以下操作:

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命令一样。这意味着即使你在将来的层中取消设置环境变量,它仍然会保留在这个层中,并且它的值可以被转储。
请参阅:编写停靠文件的最佳做法

详细信息

我更喜欢在构建期间将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,.docker.internal

在企业代理上,我们需要验证,所以我们需要配置本地代理服务器监听127.0.0.1:3128,它可以从容器通过host.docker.internal:3128访问。这样,如果我们通过VPN连接到企业网络(本地/家庭网络被阻止),它也可以在Docker桌面上工作。
设置no_proxy对于避免淹没代理服务器也很重要。
有关no_proxy相关主题的详细信息,请参见以下文章:

有时候,阅读相关文档也是很好的:

  • 环境
  • 阿根廷

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

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

还要注意的是,我们甚至不需要定义代理相关的参数,因为这些参数已经根据以下部分预定义:
Dockerfile引用-预定义的ARG

dwbf0jvd

dwbf0jvd5#

您可以在停靠文件中添加以下行

ENV http_proxy ""
ENV https_proxy ""
qvk1mo1f

qvk1mo1f6#

我发现秘密方法不起作用,因为我需要在交互模式下运行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' /根目录/.bashrc

相关问题