Dockerfile中的多次运行与单链运行,哪一种更好?
Dockerfile中的多次运行与单链运行,哪一种更好?,docker,dockerfile,Docker,Dockerfile,Dockerfile.1执行多个RUN: FROM busybox RUN echo This is the A > a RUN echo This is the B > b RUN echo This is the C > c Dockerfile.2加入它们: FROM busybox RUN echo This is the A > a &&\ echo This is the B > b &&\ echo T
Dockerfile.1
执行多个RUN
:
FROM busybox
RUN echo This is the A > a
RUN echo This is the B > b
RUN echo This is the C > c
Dockerfile.2
加入它们:
FROM busybox
RUN echo This is the A > a &&\
echo This is the B > b &&\
echo This is the C > c
每次运行RUN
都会创建一个层,因此我一直认为层越少越好,因此Dockerfile.2
越好
当运行
删除前一次运行
添加的内容(即yum install nano&&yum clean all
)时,这显然是正确的,但在每次运行
都会添加内容的情况下,我们需要考虑以下几点:
Dockerfile.1
,虽然可能稍大,但理论上下载速度会更快
echo这是D>D
)并在本地重建,Dockerfile.1
将由于缓存而构建得更快,但Dockerfile.2
必须再次运行所有4个命令
因此,问题是:哪种方法更适合制作Dockerfile?这取决于图像层中包含的内容 关键是尽可能多地共享层: 坏例子: Dockerfile.1
RUN yum install big-package && yum install package1
RUN yum install big-package
RUN yum install package1
Dockerfile.2
RUN yum install big-package && yum install package2
RUN yum install big-package
RUN yum install package2
好例子:
Dockerfile.1
RUN yum install big-package && yum install package1
RUN yum install big-package
RUN yum install package1
Dockerfile.2
RUN yum install big-package && yum install package2
RUN yum install big-package
RUN yum install package2
另一个建议是,只有当删除与添加/安装操作发生在同一层时,删除才没有那么大用处。他们的最佳实践中列出了官方答案(官方图片必须遵守这些) 最小化层的数量 你需要在两者之间找到平衡 Dockerfile和 最小化它使用的层数。谋略谨慎 关于您使用的层数 自从docker 1.10以来,
COPY
,ADD
和RUN
语句为图像添加了一个新层。使用这些语句时要小心。尝试将命令组合成一个RUN
语句。只有在可读性要求时才将其分开
更多信息:
更新:docker中的多阶段>17.05
对于多阶段构建,您可以在Dockerfile中使用多个FROM
语句。每个FROM
语句都是一个阶段,可以有自己的基本映像。在最后一个阶段中,您将使用一个最小的基本映像(如alpine),从以前的阶段复制构建工件并安装运行时需求。这个阶段的最终结果就是你的形象。因此,这就是您担心前面描述的层的地方
和往常一样,docker已经完成了多阶段构建。下面是一个简短的摘录:
对于多阶段构建,您可以在应用程序中使用多个FROM语句
Dockerfile。每个FROM指令都可以使用不同的基址
他们中的大多数人开始了一个新的建设阶段。你可以有选择地复制
从一个阶段到另一个阶段的人工制品,留下你想要的一切
不希望出现在最终图像中
关于这一点的一篇很棒的博客文章可以在这里找到:
要回答您的观点:
感谢您提醒我更新此答案。如果可能,我总是将创建文件的命令与删除相同文件的命令合并到一行中。这是因为每个
RUN
行都会向映像添加一个层,其输出实际上就是文件系统更改,您可以使用它创建的临时容器上的docker diff
查看这些更改。如果删除在不同层中创建的文件,union文件系统只需在新层中注册文件系统更改,该文件仍存在于前一层中,并通过网络传送并存储在磁盘上。因此,如果您下载源代码,将其解压缩,编译成二进制文件,然后在最后删除tgz和源文件,您真的希望所有这些都在一个层中完成,以减小图像大小
接下来,我个人根据层在其他图像中的重用潜力和预期的缓存使用情况来划分层。如果我有4个映像,所有映像都具有相同的基本映像(例如debian),我可能会将这些映像中大多数映像的公共实用程序集合拉入第一个run命令,以便其他映像从缓存中受益
查看映像缓存重用时,Dockerfile中的顺序非常重要。我看了一些很少更新的组件,可能只有在基本映像更新并将它们放在Dockerfile的较高位置时才会更新。在Dockerfile的末尾,我包含了任何快速运行且可能频繁更改的命令,例如添加具有主机特定UID的用户或创建文件夹和更改权限。如果容器包含正在积极开发的解释代码(例如JavaScript),那么将尽可能晚地添加该代码,以便重建只运行单个更改
在每一组更改中,我都尽可能地进行整合,以最大限度地减少l