Dockerfile: 我的 EXPOSE 命令放置是否正确?

3

我在工作中收到一个问题,让我对一个开源 Dockerfile进行了修改,问题归结为“你为什么改变了层数?” - 因此我正在尝试通过自己的调查来回答这个问题。

非常抱歉,该主题定义不够明确,但实质上它与Docker层如何与Docker缓存相关。

因此,在这个文档不是很规范的领域里,我正在寻找一种简洁的解释。

我的更改包括将ENV分成不同的层,将COPY操作提前,并稍后公开端口。

原始 Dockerfile(经过简化):

FROM ubuntu:latest
EXPOSE 80
ENV HELLO world \
    && DOCKER whale
RUN # Run stuff
COPY source /to/container
CMD # Do stuff

我的更改:

FROM ubuntu:latest
ENV HELLO world  
ENV DOCKER whale   # <-- Separate ENV into different layers
COPY source /to/container   # <-- Less prone to change, move earlier
RUN # Run stuff
EXPOSE 80          # <-- "Bake in" port later
CMD # Do stuff

前提条件

据我所知,从 docker-cache 的角度来看,将 ENV 变量分成不同的层是一种很好的做法,因为如果用户想要覆盖某个 ENV,则只需更改其自己层中的一个 ENV,而不是为了一个 ENV 更改包含所有 ENV 的整个层。

但是稍后添加端口 EXPOSE 就感觉对了。这是因为我使用 Docker 已经有大约 18 个月的时间了,几乎所有 Docker 的文档和指南都会在 Dockerfile 中稍后暴露端口。

根据我的经验(参加过 DockerCon2017 并参加了一些“最佳实践”课程),我也相信这一点,更容易更改/覆盖的层应该放在 Dockerfile 的后面,以更好地优化 docker-cache,从而避免太多低级别的层变化。

问题:

如果将 ENV 层分离、将 COPY 提前并将 EXPOSE 层放置在后面,是否是一种良好的做法,从优化 Docker 缓存的角度来看,是否是对原始 Dockerfile 层的整体改进?


不了解完整细节很难发表评论。RUN stuff是什么,ENV变量在哪里使用? - johnharris85
1个回答

3
虽然这个问题有一些很主观的可能答案,但我会尽量保持事实和其他来源自docker文档
Docker中正确地分层的主要目标(大致排序)有三个:
1. 正确性:某些内容需要组合/排序以确保正确性(例如apt操作应始终以apt-get update && ...开头,并且apt-get update永远不应该在单独的RUN层中) 2. 最小化层数:较少的层数通常意味着更好的构建和运行时性能。这通常意味着在可能的情况下合并层。 3. 缓存性能:将可缓存的层尽可能推到文件的最高层,注意,如果一个层被无效,则其后的所有层也被无效。
鉴于此,以下是您提出的一些观察结果:

分离ENV

根据上述第二点,应尽可能保持ENV层的组合。用户可以在运行时覆盖--env,这不会影响构建时的分层。是的,如果ENV中的一行被修改,则会使文件的其余部分无效(第3点),但通常为了性能原因而进行权衡。
COPY向上移动通常不是一个好主意,磁盘上的源代码是最有可能发生更改的内容之一,如果源代码发生更改,则从COPY层向下的所有层都将无效。
移动EXPOSE实际上并不重要。EXPOSE是一个几乎微不足道的层(除非您链接容器,否则它实际上什么也不做)。由于它是可缓存的,我会将其放在靠近顶部的位置,但它很容易计算,而且并没有真正改变。
总之,维护者在拒绝所有三个更改时是正确的,因为这会使构建和运行性能变差。

我喜欢这个答案!感谢您的清晰解释。我会稍等一下再接受,看看是否有其他人想留下答案。(虽然我认为你的难以超越。) - NonCreature0714

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接