【问题标题】:ENV, RUN produce layers, images or containers? (understanding docs question)ENV、RUN 产生层、图像或容器? (了解文档问题)
【发布时间】:2019-12-16 02:10:44
【问题描述】:

我搜索了site:stackoverflow.com dockerfile: ENV, RUN - layers or images 并阅读了Does Docker EXPOSE make a new layer?What are Docker image "layers"?

在阅读文档Best practices for writing Dockerfiles 并尝试理解这部分时:

每个 ENV 行创建一个新的中间层,就像 RUN 命令。这意味着即使您取消设置环境变量 在未来的层中,它仍然存在于该层中,其值可以 被抛弃。

我想起了上面的那部分:

旧版本的 Docker 中,将 图像中的层数,以确保它们具有性能。这 添加了以下功能以减少此限制:

只有指令 RUN、COPY、ADD 创建图层。 其他指令 创建临时中间图像,并且不增加 构建。

我读过How to unset "ENV" in dockerfile?。并重做文档页面上给出的示例,它确实证明ENV 没有取消:

$ docker build -t alpine:envtest -<<HITHERE
> FROM alpine
> ENV ADMIN_USER="mark"
> RUN unset ADMIN_USER
> HITHERE
Sending build context to Docker daemon  3.072kB
Step 1/3 : FROM alpine
latest: Pulling from library/alpine
89d9c30c1d48: Already exists 
Digest: sha256:c19173c5ada610a5989151111163d28a67368362762534d8a8121ce95cf2bd5a
Status: Downloaded newer image for alpine:latest
 ---> 965ea09ff2eb
Step 2/3 : ENV ADMIN_USER="mark"
 ---> Running in 5d34f829a387
Removing intermediate container 5d34f829a387
 ---> e9c50b16c0e1
Step 3/3 : RUN unset ADMIN_USER
 ---> Running in dbcf57ca390d
Removing intermediate container dbcf57ca390d
 ---> 2cb4de2e0257
Successfully built 2cb4de2e0257
Successfully tagged alpine:envtest
$ docker run --rm alpine:envtest sh -c 'echo $ADMIN_USER'
mark

对于ENVRUN,输出显示相同的“删除中间容器”。 我最近下载了docker,别以为它那么老

$ docker --version
Docker version 19.03.5, build 633a0ea

也许RUN instructionRUN command 是不同的东西?
ENVRUN - 它们是创建图层、图像还是容器?

【问题讨论】:

  • RUN unset ... 只生效到当前行结束;试试RUN unset ADMIN_USER &amp;&amp; echo $ADMIN_USERENV 是唯一会持续更改环境变量设置的东西。
  • @David Maze,谢谢,看起来它会工作。我也想看看我是否理解文档。

标签: docker dockerfile


【解决方案1】:

Docker 作为基于 imagecontainer 两个主要概念的容器化系统。它们之间的主要区别在于顶部可写层。当您生成一个新容器时,新的可写层将放在最后一个图像层之上。该层通常称为容器层

所有底层图像内容保持不变,并且正在运行的容器中创建新文件、修改现有文件等的每个更改都将复制到这个薄的可写层中。

在这种情况下,Docker 只存储实际的容器数据和一个镜像实例,从而减少了存储使用量并简化了底层工作流程。我会将它与 C 语言中的静态和动态链接进行比较,因此 Docker 使用 动态链接

图像是 layers 的组合。每一层只是与其前一层的一组差异。


文档说:

只有指令 RUN、COPY、ADD 创建图层。 其他指令 创建临时中间图像,并且不增加 构建。

这里的描述既不清晰也不准确,一般来说不仅这些说明在最新版本的 Docker 中创建层,文档概述。

例如,默认情况下WORKDIR 会创建一个给定的路径,如果它不存在并将目录更改为它。如果创建了新路径WORKDIR 将生成一个新层。

顺便说一句,ENV 不会导致图层创建。数据将永久存储在映像和容器配置中,没有简单的方法可以摆脱它。基本上,有两种选择,如何组织工作流:

  • 临时环境变量,它们将在当前 RUN 指令结束之前可用:
RUN export NAME='megatron' && echo $NAME # 'megatron'
RUN echo $NAME # blank
  • 清理环境变量,如果没有env或空白内容对你来说没有区别,那么你可以这样做:
ENV NAME='megatron'
# some instructions
ENV NAME=''
RUN echo $NAME

在 Docker 的上下文中,命令和指令没有区别。对于RUN,任何不更改文件系统内容的命令都不会触发永久层创建。考虑以下Dockerfile

FROM alpine:latest
RUN echo "Hello World" # no layer
RUN touch file.txt # new layer
WORKDIR /no/existing/path # new layer

最后,输出将是:

Step 1/4 : FROM alpine:latest
 ---> 965ea09ff2eb
Step 2/4 : RUN echo "Hello World"
 ---> Running in 451adb70f017
Hello World
Removing intermediate container 451adb70f017
 ---> 816ccbd1e8aa
Step 3/4 : RUN touch file.txt
 ---> Running in 9edc6afdd1e5
Removing intermediate container 9edc6afdd1e5
 ---> ea0040ec0312
Step 4/4 : WORKDIR /no/existing/path
 ---> Running in ec0feaf6710d
Removing intermediate container ec0feaf6710d
 ---> f2fe46478f7c
Successfully built f2fe46478f7c
Successfully tagged envtest:lastest

inspect 命令用于检查 Docker 对象:

docker inspect --format='{{json .RootFS.Layers}}' <image_id>

它向我们展示了从 FROM、第二个 RUN 和 WORKDIR 指令获取的三层 SHA 列表,我建议使用 dive 来探索 docker 映像中的每一层。

那么为什么它说移除中间容器而不是移除中间层?实际上,要执行RUN 命令,Docker 需要使用中间映像实例化一个容器,直到 Dockerfile 的该行并运行实际命令。然后它将容器的状态“提交”为新的中间图像并继续构建过程。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-25
    • 1970-01-01
    • 2018-08-17
    相关资源
    最近更新 更多