《Java应用提速(速度与激情)》——三、docker构建提速

简介: 《Java应用提速(速度与激情)》——三、docker构建提速

1. 背景

 

自从阿里巴巴集团容器化后,把构建镜像做为发布构建的一步后开发人员经常被镜像构建速度困扰,每天要发布很多次的应用体感尤其不好。

 

为了让应用的镜像构建尽量的少,我们几年前已经按最佳实践推荐每个应用要把镜像拆分成两部分,一部分是基础镜像,包含低频修改的部分。另一部分是应用镜像,包含高频修改的部分,比如应用的代码构建产物。但是很多应用按我们提供的最佳实践修改后,高频修改部分的构建速度依然不尽如人意。

 

现在CICD平台和集团很多镜像构建场景用的还是pouch的前身。它只支持顺序构建,对多阶段并发构建的支持也不完整,我们设想的很多优化方法也因为它的技术过于老旧而无法实施。它中很多对低版本内核和富容器的支持也让一些镜像包含了一些现在运行时用不到的文件。

 

为了跟上主流技术的发展,我们计划把CICD平台的构建工具升级到moby-buildkit,docker的最新版本也计划把构建切换到moby-buildkit了,这个也是业界的趋势。同时在buildkit基础上我们作了一些增强。

 

2. 增强

 

1) 新语法SYNC

 

我们先用增量的思想,相对于COPY增加了一个新语法SYNC。

 

我们分析Java应用高频构建部分的镜像构建场景,高频情况下只会执行Dockerfile中的一个指令:

COPY appName.tgz /home/appName/target/appName.tgz

发现大多数情况下Java应用每次构建虽然会生成一个新的app.war目录,但是里面的大部分jar文件都是从maven等仓库下载的,它们的创建和修改时间虽然会变化但是内容的都是没有变化的。

 

对于一个1G大小的war,每次发布变化的文件平均也就三十多个,大小加起来2-3 M,但是由于这个appName.war目录是全新生成的,这个copy指令每次都需要全新执行,如果全部拷贝,对于稍微大点的应用这一层就占有1G大小的空间,镜像的copy push pull都需要处理很多重复的内容,消耗无谓的时间和空间。

 

如果我们能做到定制dockerfile中的copy指令,拷贝时像Linux上面的rsync一样只做增量copy的话,构建速度、上传速度、增量下载速度、镜像的占用的磁盘空间都能得到很好的优化。因为moby-buildkit的代码架构分层比较好,我们基于dockerfile前端定制了内部的SYNC指令。

 

我们扫描到SYNC语法时,会在前端生成原生的两个指令,一个是从基线镜像中link拷贝原来那个目录(COPY),另一个是把两个目录做比较(DIFF),把有变化的文件和删除的文件在新的一层上面生效,这样在基线没有变化的情况下,就做到了高频构建每次只拷贝上传下载几十个文件仅几兆内容的这一层。

 

而用户要修改的,只是将原来的COPY语法修改成SYNC就行了。

 

如将:

COPY appName.tgz /home/admin/appName/target/appName.tgz

修改为:

SYNC appName.dir /home/admin/appName/target/appName.war

我们再来看看SYNC的效果。集团最核心的热点应用A切换到moby-buildkit以及我们的sync指令后90分位镜像构建速度已经从140秒左右降低到80秒左右

 

image.png

2) none-gzip实现

 

为了让moby- buildkit能在CICD平台上面用起来,首先要把none-gzip支持起来。

 

这个需求在docker社区也有很多讨论https://github.com/moby/moby/issues/1266

 

内部环境网络速度不是问题,如果有gzip会导致90%的时间都花在压缩和解压缩上面,构建和下载时间会加倍,发布环境拉镜像的时候主机上一些CPU也会被gzip解压打满,影响同主机其它容器的运行。

 

虽然none-gzip后,CPU不会高,但会让上传下载等传输过程变慢,因为文件不压缩变大了。但相对于CPU资源来说,内网情况下带宽资源不是瓶颈。

 

只需要在上传镜像层时按配置跳过gzip逻辑去掉,并把镜像层的MediaType

 

application/vnd.docker.image.rootfs.diff.tar.gzip

 

改成

application/vnd.docker.image.rootfs.diff.tar

 

就可以在内网环境下充分提速了。

 

3) 单层内并发下载

 

在CICD过程中,即使是同一个应用的构建,也可能会被调度到不同的编译机上。即使构建调度有一定的亲和性。

 

为了让新构建机,或应用换构建机后能快速拉取到基础镜像,由于我们以前的最佳实践是要求用户把镜像分成两个(基础镜像与应用镜像)。换编译机后需要在新的编译机上面把基础镜像拉下来,而基础镜像一般单层就有超过1G大小的,多层并发拉取对于单层特别大的镜像已经没有效果。

 

所以我们在层内并发拉取的基础上,还增加了同一层镜像的并发拉取,让拉镜像的速度提升了4倍左右。默认每100M一个分片,用户也可以通过参数来设置分片大小。

 

当然实现这层内并发下载是有前提的,即镜像的存储需要支持分段下载。因为我们公司是用了阿里云的OSS来存储docker镜像,它有很好的分段下载或多线程下载的性能。

 

4) 无中心P2P下载

 

现在都是用containerd中的content store来存储镜像原始数据,也就是说每个节点本身就存储了一个镜像的所有原始数据manifest和layers。所以如果多个相邻的节点,都需要拉镜像的话,可以先看到中心目录服务器上查看邻居节点上面是否已经有这个镜像了

 

如果有的话就可以直接从邻居节点拉这个镜像而不需要走镜像仓库去取镜像layer,manifest数据还必须从仓库获取是为了防止镜像名对应的数据已经发生了变化了,只要取到manifest后其它的layer数据都可以从相邻的节点获取,每个节点可以只在每一层下载后的五分钟内(时间可配置)提供共享服务,这样大概率还能用到本地page cache,而不用真正读磁盘。

 

image.png 

 

中心OSS服务总共只能提供最多20G的带宽,从历史拉镜像数据能看到每个节点的下载速度都很难超过30M,但是我们现在每个节点都是50G网络,节点相互之间共享镜像层数据可以充分利用到节点本地的50G网络带宽,当然为了不影响其它服务,我们把镜像共享的带宽控制在200M以下。

 

5) 镜像ONBUILD支持

 

社区的moby-buidkit已经支持了新的schema2格式的镜像的ONBUILD了,但是集团内部还有很多应用FROM的基础镜像是schema1格式的基础镜像,这些基础镜像中很多都很巧妙的用了一些ONBUILD指令来减少FROM它的Dockerfile中的公共构建指令。

 

如果不能解析schema1格式的镜像,这部分应用的构建虽然会成功,但是其实很多应该执行的指令并没有执行,对于这个能力缺失,我们在内部补上的同时也把这些修改回馈给了社区(https://github.com/moby/buildkit/pull/3053)。

相关文章
|
13天前
|
JSON Java Apache
非常实用的Http应用框架,杜绝Java Http 接口对接繁琐编程
UniHttp 是一个声明式的 HTTP 接口对接框架,帮助开发者快速对接第三方 HTTP 接口。通过 @HttpApi 注解定义接口,使用 @GetHttpInterface 和 @PostHttpInterface 等注解配置请求方法和参数。支持自定义代理逻辑、全局请求参数、错误处理和连接池配置,提高代码的内聚性和可读性。
|
14天前
|
运维 Kubernetes Docker
利用Docker和Kubernetes构建微服务架构
利用Docker和Kubernetes构建微服务架构
|
13天前
|
人工智能 API 数据安全/隐私保护
使用 Docker 一键免费部署 63.8k 的私人 ChatGPT 网页应用
NextChat 是一个可以在 GitHub 上一键免费部署的私人 ChatGPT 网页应用,支持 GPT3、GPT4 和 Gemini Pro 模型。该项目在 GitHub 上获得了 63.8k 的 star 数。部署简单,只需拉取 Docker 镜像并运行容器,设置 API Key 后即可使用。此外,NextChat 还提供了预设角色的面具功能,方便用户快速创建对话。
78 22
使用 Docker 一键免费部署 63.8k 的私人 ChatGPT 网页应用
|
22天前
|
人工智能 前端开发 Java
基于开源框架Spring AI Alibaba快速构建Java应用
本文旨在帮助开发者快速掌握并应用 Spring AI Alibaba,提升基于 Java 的大模型应用开发效率和安全性。
基于开源框架Spring AI Alibaba快速构建Java应用
|
12天前
|
监控 持续交付 Docker
Docker 容器化部署在微服务架构中的应用有哪些?
Docker 容器化部署在微服务架构中的应用有哪些?
|
12天前
|
监控 持续交付 Docker
Docker容器化部署在微服务架构中的应用
Docker容器化部署在微服务架构中的应用
|
14天前
|
运维 开发者 Docker
Docker Compose:简化容器化应用的部署与管理
Docker Compose:简化容器化应用的部署与管理
|
15天前
|
SQL Java 数据库连接
从理论到实践:Hibernate与JPA在Java项目中的实际应用
本文介绍了Java持久层框架Hibernate和JPA的基本概念及其在具体项目中的应用。通过一个在线书店系统的实例,展示了如何使用@Entity注解定义实体类、通过Spring Data JPA定义仓库接口、在服务层调用方法进行数据库操作,以及使用JPQL编写自定义查询和管理事务。这些技术不仅简化了数据库操作,还显著提升了开发效率。
29 3
|
20天前
|
存储 监控 Linux
docker构建镜像详解!!!
本文回顾了Docker的基本命令和管理技巧,包括容器和镜像的增删改查操作,容器的生命周期管理,以及如何通过端口映射和数据卷实现容器与宿主机之间的网络通信和数据持久化。文章还详细介绍了如何使用Docker部署一个简单的Web应用,并通过数据卷映射实现配置文件和日志的管理。最后,文章总结了如何制作自定义镜像,包括Nginx、Python3和CentOS镜像,以及如何制作私有云盘镜像。
99 2
|
20天前
|
JavaScript 持续交付 Docker
解锁新技能:Docker容器化部署在微服务架构中的应用
【10月更文挑战第29天】在数字化转型中,微服务架构因灵活性和可扩展性成为企业首选。Docker容器化技术为微服务的部署和管理带来革命性变化。本文探讨Docker在微服务架构中的应用,包括隔离性、可移植性、扩展性、版本控制等方面,并提供代码示例。
55 1
下一篇
无影云桌面