我们是如何将Docker构建时间缩短40%的

embedded/2024/10/10 20:00:05/

by: WL

Mapmost从设计之初,便选择了云原生道路,在软件开发过程中自然也少不了容器化技术的使用。当然,我们也为Mapmost产品中使用的所有组件构建了 docker 镜像。然而,随着时间的推移,其中一些镜像变得越来越大,CI 构建时间也越来越长。通过调研和总结经验,我们发现当构建时间超过5分钟时,会降低相关开发人员的工作效率。主要体现在以下两个方面:

  1. 开发人员如果一直等待构建完成,则浪费了大量时间;
  2. 开发人员如果去做新的事情,然后过一段时间再回来,这时候需要额外的上下文切换时间,通常也会导致效率下降。

那么接下来将为大家介绍2个构建小改动,可以大大缩短我们的构建时间。在此之前,我们已参考Docker官方给出的Dockerfile最佳实践编写了Dockerfile,如:

  1. 最小化层数
  2. 使用多阶段构建
  3. 使用最小基础映像

一、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官网体验


http://www.ppmy.cn/embedded/125510.html

相关文章

LeetCode 347.前 K 个高频元素

题目描述 给你一个整数数组 nums 和一个整数 k &#xff0c;请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。 示例 1: 输入: nums [1,1,1,2,2,3], k 2 输出: [1,2] 示例 2: 输入: nums [1], k 1 输出: [1] 提示&#xff1a; 1 < nums.length &…

简易登录注册(表单校验与登录登出);测试类;postman测试;

项目是如何创建的&#xff0c;最简易的登陆注册功能是怎么实现的&#xff0c;数据库不能明文存放密码&#xff0c;密码经过了怎么样的处理存入数据库 前端使用nodejs18 后端项目需要等待maven加载完相关依赖&#xff0c;后端使用java17 1后端 1.1 创建项目所需要的数据库 内…

文件夹作为普通文件而非子模块管理

relaxed_ik_ros2 文件夹下存在 .gitmodules 文件和 .gitignore 文件。这说明该目录已经被 Git 识别为子模块。 要将这个文件夹作为普通文件而非子模块管理&#xff0c;你可以按以下步骤操作&#xff1a; 1. 删除子模块配置 首先删除 .gitmodules 文件中的子模块配置。你可以…

Midjourney零基础学习

Midjourney学习笔记TOP05 Midjourney的各种参数设置 Midjourney的用户操作界面没有醒目的工具栏、属性栏&#xff0c;所有的操作都是通过调用各种指令和参数进行的。 【Niji version】 这里只讲解&#xff1a;V4 和 V5 两种模型 Niji V4的这个模型版本主要是用来生成动画和插…

【WebGIS】基础知识及工具介绍

文章目录 介绍基础知识1、地图服务规范2、地理坐标、世界坐标、屏幕坐标。3、坐标系分为两类4、基于 WGS84 测量系统的坐标系为两种5、常见的坐标系6、常见的地图使用的坐标系7、常见的 gis 库默认坐标系使用工具[桌面端软件]1、ArcView、ESRI ArcGIS Desktop与ArcGIS Pro等。2…

《C++代码热更新:为高效开发注入新活力》

一、引言 在软件开发的过程中&#xff0c;我们常常面临着这样的挑战&#xff1a;当程序已经部署到生产环境后&#xff0c;发现了一些需要紧急修复的 bug 或者需要添加新的功能。传统的方法是停止程序运行&#xff0c;进行代码修改&#xff0c;然后重新编译、部署&#xff0c;这…

SOD贴片二极管封装形式与尺寸( SOD-123/323/523)

目前&#xff0c;贴片二极管已经在大多数应用中取代了传统的引线式产品。其中&#xff0c;SOD封装是大部分贴片二极管的安装形式。 SOD衍生了一系列二级管封装形式 SOD是小外形二级管&#xff08;Small Outline Diode&#xff09;的英文缩写&#xff0c;目前已经衍生了一系列标…

vue双向绑定/小程序双向绑定区别

Vue双向绑定与小程序双向绑定在实现方式、语法差异以及功能特性上均存在显著区别。以下是对这两者的详细比较&#xff1a; 一、实现方式 Vue双向绑定 Vue的双向绑定主要通过其响应式数据系统实现。Vue使用Object.defineProperty()方法&#xff08;或在Vue 3中使用Proxy对象&am…