Dockerfile:我的位置是否正确?

当我使用开源的Dockerfile的时候遇到了一个问题,这个问题归结为“你为什么要改变图层? – 所以我试图用我自己的调查来回答这个问题。

我很抱歉,这个问题没有很好的定义,但本质上是关于码头层如何与码头缓存相关联。

所以我在一个没有很好记录的地方寻找一个优雅的解释。

我从原来的Dockerfile中将ENV分离到不同的层,更早地移动一个COPY,以及稍后公开端口。

原来的(简体):

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需要在它自己的层中改变,而不是改变整个图层包含了所有的ENVs。

但是稍后添加端口EXPOSE – 它感觉不错。 这是因为我已经使用了大约18个月的Docker,几乎所有的Docker的文档和指南都在稍后的Dockerfile中公开了端口。

我也相信这是基于我的经验(参加DockerCon2017并参与一些“最佳实践”类) ,更容易发生变化/覆盖的层应放置在Dockerfile中 ,以便更好地优化Docker -cache没有那么多的低层次的变化。

题:

我的看法是正确的(或者愚蠢的),假设分离ENV层,更早地移动COPY,以及放置EXPOSE层是一种很好的做法,并且从优化Docker缓存的角度对原始的Dockerfile层进行了全面的改进。

虽然这个问题有一些很大的可能的答案,我会试图保持事实和其他东西从码头的文档来源

泊坞窗中的图层合适分层有三个目标(大致排序):

  1. 正确性:有些东西需要合并/排序以保证正确性(例如apt操作应始终以apt-get update && ...开头,并且apt-get update不应该在单独的RUN层中
  2. 最小化图层:通常意味着更少的图层对于构建和运行时都有更好的性能 这通常意味着在可能的情况下组合层
  3. 缓存性能:尽可能将可缓存层推入文件中的最高层,请注意,如果某层失效,则该层之后的所有层也将失效

鉴于此,以下是您提出的一些观察结果:

分离ENV

根据上面的(2),你应该尽可能地保持ENV层的组合。 用户可以在运行时覆盖--env ,这不会影响构建时间分层。 是的,如果其中一条ENV行在源代码中被修改,它会使文件的其余部分无效(3),但通常由于性能方面的原因而被交换。

移动COPY

通常这不是一个好主意,磁盘上的源代码是最有可能改变的事情之一,如果源改变, COPY层向下的所有层都是无效的

移动EXPOSE

这真的没有关系。 EXPOSE是一个几乎平凡的层(事实上,除非你连接容器,否则什么也不做)。 由于它是可缓存的,所以我把它放在顶端,但再一次,计算并不真正改变。

概要

tl; dr对于所有这三个变化,维护人员都是正确的,因为这会使构建和运行性能变差。