镜像打包Dockerfile文件常见规范问题

修改dockerfile主要影响镜像的打包方式,一般并不会影响应用的实际运行(调整后例如使用mini镜像导致组件依赖缺失等环境问题除外,这部分可以通过添加组件依赖解决)。

本文的目的就是展示在工作中遇到的dockerfile经常出现的一些不规范的地方以及具体的可优化点。

优化调整不规范dockerfile文件的主要好处:
a. 减少应用构建时的镜像打包耗时(减少镜像的更新层数)
b. 缩小应用镜像的包大小,提升应用部署时的镜像拉取速度(减少镜像层数以及清理无用的安装包缓存)

分类问题总结

RUN yum指令后应以yum clean all收尾

【原因】一些应用需要通过yum指令安装依赖的组件,在使用yum指令之后没有在最后使用yum clean all进行安装包缓存的清理,这会使最终的镜像包包含无用的安装包文件增加了镜像包的大小

【解决方案】在所有yum指令的最后增加一条yum clean all

【收益】根据实际安装包的大小获得相应的容量缩减收益

例如:
paradin
调整后:
paradin

RUN yum或RUN rpm指令应在COPY指令之前

【原因】目前大部分应用镜像出现该规范问题主要是在copy应用主包之后,使用RUN指令进行应用包的解包操作,以及部分应用将新增的组件安装等指令直接在copy应用主包之后添加

【解决方案】对于新增的组件安装等指令迁移至前面统一的RUN指令里,通过&&实现同类型或类似变化频率的指令在同一个RUN层。对于对应用包解包操作需要根据应用自身需求确定是否可以移除(可以检查应用启动文件是否存在检查应用包并解包的脚本,如果存在则可以放心的在dockerfile移除主包解压指令,同时当前各应用的主包压缩模式小文件存在情况很少,所以对应用的首次启动耗时不会带来影响。从目前收集的几个应用看均可移除该指令)。

【收益】a. 减少镜像分层,获得分层聚合带来的容量缩减收益
b. 应用解压后占用的容量缩减收益
c. 降低镜像构建耗时,特别当使用yum指令用于安装依赖组件时,可以得到较高的耗时优化收益

不应该超过3条连续RUN命令/Dockerfile指令不应超过20条

【原因】一些应用为了添加应用的依赖组件或环境配置,并没有把相同类型或变化频率的指令集中在一个RUN层,而是为每一个sh指令配置RUN指令。一条RUN指令会对应一个镜像分层,过多的RUN指令会导致最终的镜像容量变大。

【解决方案】以动静分离原则,采用不变更指令、偶尔变更指令、频繁变更指令设计尽量将少RUN指令,根据依赖关系和变化频率将各sh指令分配至对应的RUN层,以&&分割符实现批量指令配置

【收益】降低镜像层变更同步的影响,提升镜像构建的push同步速度,同时因镜像层数减少带来部分容量缩减的收益

base镜像体积不应超过2G,能用最小的基础镜像就用最小的,这个不多说了

CMD/ENTRYPOINT/EXPOSE/LABEL指令位置应在COPY/RUN之前

【原因】一般ENTRYPOINT基本上是固定不变的,所以放在COPY/RUN之前可以减少因COPY/RUN层变动导致分层缓存失效而被动重新构建分层
【解决方案】将ENTRYPOINT指令放在所有的COPY/RUN之前即可
【收益】目前ENTRYPOINT指令用于指定应用启动目录,因此实际对镜像影响很小,所以调整后对当前镜像大小和构建时长没有什么影响,仅用于满足集团dockerfile的执行规范

存在部分重复的配置指令

【解决方案】部分dockerfile配置存在重复指令的情况,特别是ENV配置,需要将ENV配置集中在一条ENV指令中减少镜像层数,同时去除不必要的重复配置
【收益】减少镜像层数,获得镜像层数减少带来小量的缩减的收益
paradin

paradin

构建时发生变化的层不应该超过3层

【原因】一般采用动静分离原则进行指令分层优化后,大部分情况下构建变化不会超过3层。出现这个可能原因有如下两个:
1、Dockerfile指令进行了较大的调整后首次进行编译,导致之前的分层缓存失效需要对变化的层重新构建
2、Dockerfile指令未按动静分离原则进行分层,将需要经常变化的分层内容对应的指令写在了前面,导致后面的分层被动进行重新构建(docker构建逻辑:当前分层如果需要重新构建,则后续的分层不论是否变化都需要强制重新构建)
【解决方案】
1、对于第一种情况,只要再重新构建一次即可消除该问题,即在每次对dockerfile做较大指令调整后可连续进行2次编译来查看是否存在该问题
2、对于第二种情况,检查Dockerfile指令是否存在每次编译都需要变化的内容写在了前面,分析确认各个指令对应的内容的变化频率,采用不变化、偶尔变化、频繁变化从上至下的方式整理编写到Dockerfile,典型是主应用包拷贝指令,因为应用包每次构建一定会发生变化,所以在拷贝主应用包指令后面的其他指令一定会被强制重新构建。
【收益】减少镜像变化层数,降低镜像构建耗时
例如:
paradin

paradin

感谢您请我喝咖啡~O(∩_∩)O,如果要联系请直接发我邮箱chenx1242@163.com,我会回复你的
-------------本文结束感谢您的阅读-------------