by: WL
Mapmost从设计之初,便选择了云原生道路,在软件开发过程中自然也少不了容器化技术的使用。当然,我们也为Mapmost产品中使用的所有组件构建了 docker 镜像。然而,随着时间的推移,其中一些镜像变得越来越大,CI 构建时间也越来越长。通过调研和总结经验,我们发现:当构建时间超过5分钟时,会降低相关开发人员的工作效率。主要体现在以下两个方面:
- 开发人员如果一直等待构建完成,则浪费了大量时间;
- 开发人员如果去做新的事情,然后过一段时间再回来,这时候需要额外的上下文切换时间,通常也会导致效率下降。
那么接下来将为大家介绍2个构建小改动,可以大大缩短我们的构建时间。在此之前,我们已参考Docker官方给出的Dockerfile最佳实践编写了Dockerfile,如:
- 最小化层数
- 使用多阶段构建
- 使用最小基础映像
一、BuildKit vs Buildx
让我们首先了解下 Buildkit 和 Buildx,他们通常可以互换使用,但它们并不相同。
1. Buildkit
BuildKit 的诞生旨在取代Docker传统的构建引擎。自 Docker Desktop 以及 Docker Engine 23.0 版本起,BuildKit 成为默认构建器,其优化了构建过程的效率和性能,提供了许多新特性,如:
- 更优的缓存能力
- 并行构建
- 基础镜像的懒拉取(≥ Buildkit 0.9)
如果需要在 23.0 之前的 docker 版本中使用 BuildKit,常见方法如下:
DOCKER_BUILDKIT=1 docker build --platform linux/amd64 . -t someImage:someTag
DOCKER_BUILDKIT=1 docker push someImage:someTag
2. Buildx
Buildx是Docker的一个插件,支持Buildkit的全部特性。Buildx的产生是因为Buildkit的许多新配置选项,无法向后兼容集成到docker build命令中。
除了提供构建镜像的功能,Buildx还可以管理多个构建器。在CI/CD中,我们使用同一个Docker就能很好的隔离具有不同配置的构建器,而以往我们常常需要在不同的Docker中构建。
如何创建并使用Buildx的基本操作如下:
docker buildx create --bootstrap --name builder
docker buildx use builder
二、 远程存储构建缓存信息
我们介绍的第一个方法:将镜像缓存在远程仓库。
这样,即使在不同机器上进行构建也会用到缓存,典型的使用场景正是在CI/CD中使用不同构建器构建各种镜像。当我们使用默认的构建器时,每个BuildKit实例仅能维护并使用自己的缓存。当在不同的构建器之间切换时,缓存不会共享。因此存在重复拉取镜像。但如果使用外部远程缓存特性,我们则可以指定用于推送和拉取镜像的远程位置,构建时会大大缩短时间。要使用外部缓存,通常指定 --cache-to
和 --cache-from
选项结合buildx
。具体形式如下:
docker buildx build --platform linux/amd64 . \
-t someImage:someVersion - push \
--cache-to type=registry,ref=someCachedImage:someVersion,mode=max
--cache-from type=registry,ref=someCachedImage:someVersion
以上指令告诉构建器在someCachedImage:someVersion
镜像中查找缓存。当构建完成后,新的构建缓存被推送到相同的镜像中, 覆盖旧缓存。mode=max 表示存储每一层的构建信息,即使是结果镜像中不使用的层(如多阶段构建时中间阶段产生的构建信息)。mode默认值为min,此时只存储结果图像中存在的层的构建信息。
三、添加、复制文件到镜像时使用link选项
自dockerfile1.4语法开始,其对COPY和ADD指令增加了新的选项:--link
# syntax=docker/dockerfile:1.4
FROM ...
COPY --link foo bar
1.在没有使用--link
选项时,将某个文件复制到某个目录,需要先完成所有前面的指令,即此时父层快照必须存在,构建器会将父层复制到新快照中,否则如果目录不存在,COPY指令将执行失败。在构建完导出结果镜像时,通过“differ”组件比较所有快照然后将它们合并,从而创建包含每个快照中添加的文件最终镜像文件。
2.通过设置 --link
选项,COPY 指令会将文件复制到一个完全新的快照中,而不是基于父层进行添加。在最后生成结果镜像时,这个新快照也会被转换成一个单独层,该层会被链接到父层中。链接操作通常只是涉及一些元数据的更改,此时,构建器无需访问或移动任何文件。即使某些层存在于远程仓库中,也可以在不需拉取或推送它们的情况下远程完成这一操作。
使用该选项前后对比如下:
图源:https://www.docker.com/blog/image-rebase-and-improved-remote-cache-support-in-new-buildkit
使用--link
选项的主要优势是文件不再依赖于父层。只要文件没有改变,即使父层改变了,自身层也可以被复用。得益于此,构建器能够并行执行多层复制数据,大大缩短构建时间。
在这篇文章中,我们介绍了在Mapmost产品开发中使用到的2个小技巧,这样就实现了整体的Docker构建时间减少40%。
Mapmost秉持着“让人与机器联合创作成为新常态”的理念,综合运用多项前沿技术,以SDK二次开发或零代码的方式为工厂、企业等提供一站式数字李生解决方案,现已广泛应用于各行业数字化项目建设。
点击这里跳转Mapmost官网体验