与 Harbor 构建高效的镜像加速工作流

3d45dbdbb91bf9d672a918091d368fa5.gif

镜像是容器的基础,如今有很多用户在实践使用 Harbor 作为镜像存储与分发方案,本文介绍了 Harbor 在支持镜像加速方面的能力,以及 Nydus 这种改进的镜像格式,用于解决镜像在网络,存储,端到端可信方面的问题。使用 Harbor 结合按需加载,P2P 分发与预热技术加速镜像拉取,可以将容器启动时间从分钟级降低到秒级。

OCI 镜像格式

049fb7b6509fd2cd9b66a8cb8e8321ff.png

OCI 容器镜像格式是由 tar/tar.gz/tar.zstd 等格式的多层数据组成的,在容器创建时 Containerd 等组件需要将所有层分别下载并且解压到目录下,再用 OverlayFS 这类文件系统按目录顺序堆叠起来,提供给容器一个只读的 RootFS 文件系统。这样的分层设计可以在多个镜像间复用数据,做到增量构建,但同时它也有很多局限。

数据全量下载

下载并解压镜像层是一个非常耗时的过程,有篇 研究[1]表明,镜像拉取操作所需的时间占容器启动时间的 76%,但只有约 6.4% 的数据在运行时被容器读取,这意味着大量可能用不到的数据会占用网络带宽而拖慢启动速度。

元数据更新成本高

镜像中文件的元数据和数据是以 tar 格式放在同一层的,因此文件名、权限位等元数据的改动,会导致整个镜像层的 Hash 变化。例如一个 10GB 的层,重命名了其中一个文件,即使文件数据部分没有更新,也会导致整个镜像层在构建阶段重新压缩、上传、存储以及在运行时重新下载。

不被察觉的冗余数据

在 Dockerfile 指令中删除文件时,根据 OCI Image Spec[2],会在 Upper 层生成一个 Whiteout 特殊空文件表示删除,而修改(甚至只修改元数据)文件,会在 Upper 层生成完整的新文件。这两种情况下,旧版本文件还存在于 Lower 层,在运行时,用不到的旧版本数据依然会被下载和解压,镜像越来越复杂时这样的问题很难察觉,导致镜像体积很难优化。

数据去重效率低

镜像只能以层的粒度,以 Hash 比较的方式在存储和下载中去重,但在文件内、层内、层与层之间、镜像与镜像间等多个维度上都可能存在重复数据,镜像越复杂,问题越明显。

本地镜像数据不可信

镜像下载后可以通过 Hash 校验一致性,但在容器启动后,访问镜像数据过程中不会再次校验数据完整性,无法知道 RootFS 中的文件是否被篡改,这导致镜像在运行时是不可信的。

重构 OCI 镜像格式

要解决上述数据全量下载的问题,一种思路是按需加载,即容器启动时只拉取需要读取的部分数据,而不是整个镜像层。但传统镜像层都是先用 tar 格式打包,再使用 gzip/zstd 等压缩算法压缩整个 tar 数据,无法直接做到随机访问的解压。

f0d942a119492ebd4e4372f5a812bbc4.png

这里简单介绍一下 Nydus 镜像加速框架[3],Nydus 基于高性能只读文件系统格式 EROFS[4] 扩展出了 RAFS(Registry Acceleration File System) 文件系统格式,它将 gzip/zstd 镜像层,转换为 RAFS 数据和元数据两大部分。

镜像构建

  • RAFS 文件数据部分,按指定 Size(如 1MB)大小切割成小块数据(Chunk),例如一个 10.5MB 的文件会切割成 11 个小的 Chunk,将每个 Chunk 块使用 Zstd/LZ4 等方式单独压缩,然后聚合在一起打包到一个文件(Blob)中,在打包过程中可以根据 Chunk Hash 或外部 Chunk 字典做去重,以降低镜像的增量尺寸;

  • RAFS 文件元数据部分,全部存放在一个元数据(Metadata)文件中,除了文件元信息外,它还记录了文件有哪些 Chunk,Chunk 的 Hash 值,以及在上述 Blob 中的偏移位置(Offset)

  • 另外,Nydus 镜像层始终比 OCI v1 镜像多了一层 Overlayed Metadata,这层 Metadata 是所有层的元数据堆叠,它通常很小,例如几十 GB 的镜像,Overlayed Metadata 通常有 10MB。

镜像运行

Nydus 支持 FUSE 用户空间和内核态文件系统两种方式来实现按需加载,以 FUSE 实现为例,镜像拉取过程如下:

  • 容器创建阶段,由 Containerd 配合 Nydus Snapshotter 组件先拉取镜像的 Overlayed Metadata 层,这层很小速度较快;

  • Nydus Snapshotter 组件启动 Nydus Daemon(Nydusd)进程,创建 FUSE 挂载点作为容器 RootFS 目录,此时容器就可以启动了;

  • 容器启动后读取数据时,Nydusd 处理容器 RootFS 发起的 FUSE read 请求,根据 Metadata 层信息,从远端镜像中心拉取部分 Chunk 数据,然后解压,校验,缓存到本地并返回给容器。

b2ec98e464f7cc9f274c3a297e85f4bc.png

Nydus 通过重构镜像格式,可以解决上述传统 OCI 镜像的诸多问题,且能够做到 OCI 生态的兼容,另外 Nydus 也支持了内核态的 EROFS + FSCache[5] 按需加载方案,有更好的性能和更低的开销。下图为容器端到端的启动时间测试,传统 OCI 镜像随着镜像尺寸增大耗时明显增高,Nydus 镜像可以保持平稳。

7b0b76b31b7ec1b064895dcd406339e8.png

引入 P2P 的按需加载

Harbor 集成的 Distribution[6] 支持 HTTP Range[7] GET 读取镜像层的部分小块数据以支持按需加载,很多业务容器在启动阶段就会读取大量镜像数据,或者在服务期间读取大量数据,这会发起大量小块 HTTP IO 请求,另外容器流量到来时再做按需加载会对在线业务有性能影响。为了解决这些问题,Nydus 支持按需时后台线程预取数据,以及小块 IO 请求的合并,可以降低 HTTP 请求量。

在大规模部署场景下,尤其是例如 AI 模型镜像,大量 HTTP 请求还是会给单点镜像中心带来压力,集群请求延迟增高。Dragonfly[8] 是基于 P2P 的文件分发和镜像加速框架,能够提高大规模文件传输的性能,最大限度的利用节点之间的闲置带宽,减少镜像中心回源流量,它也支持在首次 Range GET 请求后在节点间预热整个 Blob 数据。从来自蚂蚁集团大规模部署实践来看,Nydus 与 Dragonfly 架构支撑了每日百万级别的加速镜像容器创建,还没有遇到业务报告因为按需加载而导致的性能抖动。

dc623fb978da86847b9dfa5701bd0774.png

Harbor 镜像转换服务

Harbor 可以很好地支持镜像加速格式,并且也支持了 P2P 预热[9],在用户 Push 镜像后触发 P2P 服务为集群预热镜像数据,提高部署时镜像数据分发速度。加速镜像格式和普通镜像格式不同,构建或转换步骤是必须的,可以使用 Buildkit[10] 从 Dockerfile 直接构建加速镜像,也可以使用 Nerdctl[11] 或 Nydusify[12] 转换工具。为了让 Harbor 进一步支持用户透明地使用加速镜像,Harbor 的子项目 Acceld[13] 诞生了,Acceld 为 Harbor 提供了自动转换加速镜像的能力。

Acceld 是一个通过 Harbor Webhook 扩展的服务,它是一个通用的加速镜像转换框架。当用户推送镜像时,Harbor 向该服务发送 Webhook 请求,通过其集成的 Nydus、eStargz 等转换驱动完成镜像的转换。

Acceld 服务缓存

在用户 Push 镜像后,Acceld 创建加速镜像转换任务,它需要先拉取原始镜像数据,转换完成后将加速镜像 Push 回 Harbor,Acceld 支持本地与远端两种缓存:

  • 本地缓存:用于缓存拉取后的源镜像层,避免相同源镜像层的重复拉取;

  • 远端缓存:用于缓存转换后的镜像层,避免相同镜像层的重复转换/推送。远端缓存实际上也是一种镜像,它使用类似 LRU 的方式在远端记录最近转换过的 layers,下次转换时根据转换过的缓存记录就可以跳过重复层的转换,以提高转换速度。

下表是 wordpress 镜像前后两次转换的性能数据,第二次是基于 wordpress 镜像添加增量层(几 MB 数据)构建的新镜像,没有本地缓存,只命中远端缓存的情况:

67c68e298576347f900f880e961951b1.png

Acceld 垃圾回收

作为常驻服务,Acceld 有自己的本地镜像缓存垃圾回收,它使用 Containerd 的租约[14]管理机制(但并不依赖 Containerd 服务),能够按照 LFRU 的(先 LFU 再 LRU)顺序清理缓存,优先删除不常用的 Upper 镜像层数据。

Acceld 可扩展性

Acceld 提供了一个内置的可扩展 Driver 方法,允许支持其他类型的镜像格式转换,框架会处理 Pull,Push 及 Cache 操作,格式提供商只要实现一个 Drvier 接口[15]

OCI Reference Type

OCI 镜像设计原则是 Immutable 的,也就是当 Tag & Push 一个镜像后,理论上不应该再次修改镜像内容后覆盖(虽然可以这么做)。Cosign[16]/Notation[17] 项目可以为镜像签名并验证镜像完整性,在之前这类附件只能作为单独的 Tag Push 到镜像中心,这会污染镜像列表,也需要跟踪它和原始镜像的关联关系,在 Harbor 中是特殊处理了这类附件的,在 UI 展示中将签名标记为一个图标,并处理了诸如镜像复制等操作,让签名始终跟随着镜像。

对于以上类似用例,在 OCI Image Spec v1.1 中,新增了 Reference Type 的支持,在附件 Manifest 上使用 subject[18] 字段记录原始镜像 Manifest 的 Digest,能够让构件 Manifest 间产生关联。另外可以使用 OCI Distribution Spec v1.1 中定义的 Referrers API[19] 发现镜像关联了哪些附件 Manifest,这两个特性都已被 Harbor 支持。

这对于镜像加速非常有用,在很多情况下加速镜像是由普通镜像转换而来,或者用户需要同时保留两种版本镜像,用于非按需场景的 Fallback,或镜像加速的方案过渡。Harbor v2.9 版本中也为 Nydus 更好地支持了 Reference Type:

  • 原始镜像关联的 Nydus 镜像,在 Harbor UI 上会被级联展示并显示 Nydus 镜像图标,这让镜像列表更加干净,且关联关系一目了然;

  • 删除原始镜像时,Harbor 会自动删除关联的 Nydus 镜像,这样用户不再需要考虑如何同时 GC 两种镜像。

485ac3eb0481a11a6babe5d1f63bcd78.png

在使用 Nydus Snapshotter[20] 运行普通镜像时,它可以使用 Harbor 提供的 Referrers API[21] 自动发现是否有关联的 Nydus 镜像,如果有则直接运行,实现用户无感的镜像加速。

无需转换的加速镜像格式

上面提到的按需加载方案需要重新制作镜像格式,这给镜像的转换和存储都带来了额外开销。实际上 Gzip 也是可以随机访问压缩的,但需要构建一个解压寻址索引,参考 zran[22] 和 SOCI[23] 实现,Nydus 也支持了 zran 索引格式,它的特点是:

  • 分析 gzip 镜像层生成解压寻址索引,而不是转换整个镜像层格式,这比完整转换一个镜像要快很多;

  • 生成的索引很小,不会生成额外格式的数据,可以节省镜像中心大量存储,不用存储两份数据。

node:19.0 镜像为例,可以看到 Zran 索引镜像要小很多,转换耗时也比 Nydus Native 镜像更低,由于 Zran 有部分读放大,运行时按需加载的数据量要偏大,启动耗时会高一点,但这相比普通 OCI 镜像依然有优势,足以应对大多数场景。

a1ccbc34c7456162e45638a09280f334.png

Acceld 也实现了 Nydus Zran 镜像格式的转换[24],通过配合本地与远端缓存,有更好的转换速度。

镜像加速性能收益

我们引用了 Dragonfly 文档[25]中的测试数据,在单机上测试了不同语言镜像运行版本命令的容器启动时间,例如 Python 镜像运行启动命令为 python -V

d229baa5d3430bbeaa757845f78bdb65.png

  • OCI v1:使用 Containerd 直接拉取 OCI 普通镜像并启动容器的耗时;

  • Nydus Cold Boot:使用 Containerd 拉取 Nydus 镜像,没有命中任何缓存并且启动容器的耗时;

  • Nydus & Dragonfly Cold Boot:使用 Containerd 通过 Nydus + Dragonfly P2P 拉取镜像,没有命中任何缓存并且启动容器的耗时。

测试表明使用 Nydus 与 Dragonfly P2P 后,相对于 OCI 普通镜像能够有效减少镜像下载时间,有缓存(Dragonfly Peer Cache & Nydus Cache)的情况下效果更好,这在大规模集群情况下更加明显,以下是字节跳动批量扩容 Nginx Pod 的测试数据,可以看到 OCI 普通镜像启动耗时随着并发量越大扩容越慢,但结合 Nydus 与 Dragonfly 在性能上无明显影响:

aa96726781510b9f8ea3bd1794b3f2fe.png

Harbor 镜像加速工作流

基于上述基础,一个完整的镜像加速工作流如下:

  1. 用户使用 Docker/Buildkit 等构建工具 Push OCI 普通镜像(Step 1)

  2. Harbor Acceld 帮助自动转换为加速镜像 & 使用 P2P 服务预热镜像,参考 Acceld & Harbor Preheat(Step 2, 3, 4)

  3. 运行时 Snapshotter 运行加速镜像,并通过 P2P 加速按需拉取,参考 Nydus Integration[26](Step 5, 6)

5d51de334a94508470842eacf4463f59.png

当然这不是唯一的镜像加速工作流解决方案,它的目标是做到自动化与用户无感,使用这一基础设施能够让用户镜像无缝切换到加速版本,作为一种实践参考。

参与社区

Harbor:https://goharbor.io/
Harbor Acceld:https://github.com/goharbor/acceleration-service
Dragonfly:https://d7y.io/
Nydus:https://nydus.dev/

参考链接

[1]研究:https://www.usenix.org/node/194431

[2]OCI Image Spec:https://github.com/opencontainers/image-spec/blob/main/layer.md#representing-changes

[3]Nydus 镜像加速框架:https://nydus.dev/

[4]EROFS:https://docs.kernel.org/filesystems/erofs.html

[5]EROFS + FSCache:https://github.com/dragonflyoss/image-service/blob/master/docs/nydus-fscache.md

[6]Distribution:https://github.com/distribution/distribution

[7]Range:https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Range

[8]Dragonfly:https://d7y.io/

[9]P2P 预热:https://goharbor.io/docs/2.9.0/administration/p2p-preheat/

[10]Buildkit:https://github.com/moby/buildkit

[11]Nerdctl:https://github.com/containerd/nerdctl/blob/main/docs/nydus.md

[12]Nydusify:https://github.com/dragonflyoss/image-service/blob/master/docs/nydusify.md

[13]Acceld:https://github.com/goharbor/acceleration-service

[14]租约:https://github.com/containerd/containerd/blob/main/docs/garbage-collection.md

[15]Driver 接口:https://github.com/goharbor/acceleration-service/blob/main/docs/development.md#driver

[16]Cosign:https://github.com/sigstore/cosign

[17]Notation:https://github.com/notaryproject/notation

[18]subjece:https://github.com/opencontainers/image-spec/blob/main/manifest.md#example-image-manifest

[19]Referrers API :https://github.com/opencontainers/distribution-spec/blob/main/spec.md#listing-referrers

[20]Nydus Snapshotter :https://github.com/containerd/nydus-snapshotter

[21]自动发现:https://github.com/containerd/nydus-snapshotter/blob/1e090da3b512feaa933ee46a5db2019ac32aa0ed/misc/snapshotter/config.toml#L109C8-L109C8

[22]zran:https://github.com/madler/zlib/blob/master/examples/zran.c

[23]SOCI:https://github.com/awslabs/soci-snapshotter

[24]转换:https://github.com/goharbor/acceleration-service/blob/f902238337fe09d671861d2f2e6eb71e64c20e1a/misc/config/config.nydus.ref.yaml#L56

[25]文档:https://d7y.io/docs/next/setup/integration/nydus/#performance-testing

[26]Nydus Integration:https://github.com/dragonflyoss/image-service/blob/master/docs/containerd-env-setup.md

Nydus Star 一下✨:
https://github.com/dragonflyoss/image-service

参考链接

32650e04c6c0eb6b643b535a17dbf797.png

Nydus 加速镜像一致性校验增强

784f706fbc460727a855b31567d2141f.png

Nerdctl 原生支持 Nydus 加速镜像

7b131b97dcebbda2dbcd9f482e817fd8.png

Dragonfly 发布 v2.1.0 版本!

239fb634f067014014f7bf8c923e3e2f.png

Dragonfly 中 P2P 传输协议优化

d1525dacf558cbbcb45f7043a47e2c6f.jpeg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/161628.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GPT绘制流程图咒语

【咒语】下面是我的一篇论文选取部分,为了让读者更好理解,我准备画一张图,请你阅读后为我设计一下这个图应该怎么画,更有说服力,更容易理解 论文片段: 多模态数据融合研究的基础在于有效的数据采集。首先&a…

git学习——第4节 时光机穿梭

我们已经成功地添加并提交了一个readme.txt文件,现在,是时候继续工作了,于是,我们继续修改readme.txt文件,改成如下内容: Git is a distributed version control system. Git is free software. 现在&…

Spring源码解析——事务增强器

正文 上一篇文章我们讲解了事务的Advisor是如何注册进Spring容器的,也讲解了Spring是如何将有配置事务的类配置上事务的,实际上也就是用了AOP那一套,也讲解了Advisor,pointcut验证流程,至此,事务的初始化工…

CAD图形导出为XAML实践

文章目录 一、前言二、方法与实践2.1 画出原图,借第三方工具导出至指定格式2.2 CAD导出并转换2.3 两种方法的优劣2.3.1 直接导出代码量大2.3.2 导入导出需要调参 三、总结 一、前言 上位机通常有一个设备/场景界面,该界面用于清晰直观地呈现设备状态。 …

Yakit工具篇:子域名收集的配置和使用

简介(来自官方文档) 子域名收集是指通过各种技术手段,收集某个主域名下所有的子域名列表。子域名是指在主域名前面添加一级或多级名称的域名。例如,对于主域名example.com,其子域名可以是www.example.com、mail.example.com、blog.example.c…

触控笔哪个牌子好用?主动电容笔和被动电容笔的区别

主动式电容笔和被动式电容笔两者最大的不同之处在于主动式电容笔的应用范围更大,可以兼容各种不同的电容屏幕。随着人们对其认识的不断深入,其应用范围也在不断扩大。而且国产的主动式电容笔,也在不断的更新换代,重力越来越多&…

Django使用Token认证(simplejwt库的配置)

目录 官网文档安装项目配置拓展配置 官网文档 https://django-rest-framework-simplejwt.readthedocs.io/en/latest/ 安装 pip install djangorestframework-simplejwt项目配置 REST_FRAMEWORK {...DEFAULT_AUTHENTICATION_CLASSES: (...rest_framework_simplejwt.authent…

c#设计模式-行为型模式 之 访问者模式

🚀简介 封装一些作用于某种数据结构中的各元素的操作,它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作。 访问者模式包含以下主要角色 : 抽象访问者(Visitor)角色:定义了对每一个元素 (E…

pytorch3D Windows下安装经验总结

一、说明及准备工作 最近在安装pytorch3D的时候遇到了很多问题,查了很多博客,但发现讲的都不太全,所以特将自己的及收集到的安装过程经验总结如下。我是在Anaconda中虚拟环境下安装的。 1.1准备工作 官方安装教程如下:https://…

英特尔 SGX 技术概述

目录 介绍概述指示结构Memory安全区页面缓存Enclave Page Cache (EPC)安全区页面缓存映射Enclave Page Cache Map (EPCM) Memory ManagementStructures页面信息Page Information (PAGEINFO)安全信息Security Information (SECINFO)分页加密元数据Paging …

小程序入门——详细教程

🎬 艳艳耶✌️:个人主页 🔥 个人专栏 :《Spring与Mybatis集成整合》《Vue.js使用》 ⛺️ 生活的理想,为了不断更新自己 ! 1.微信小程序 入门 1.1什么是小程序? 2017年度百度百科十大热词之一 微信小程…

小程序的console中出现:。。。不在以下 request 合法域名列表中,请参考文档:。。。的报错解决

报错效果: 其实这个报错不代表自己的代码有问题 但是本强迫症研究了一下,按照以下方法关掉就不会显示这个报错了。 点微信开发者工具中的右上角的详情。点本地设置。勾选不校验。。。HTTPS证书。 即可关闭该报错:

java springboot VUE粮食经销系统开发mysql数据库web结构java编程计算机网页源码maven项目

一、源码特点 springboot VUE 粮食经销系统是一套完善的完整信息管理类型系统,结合springboot框架和VUE完成本系统,对理解JSP java编程开发语言有帮助系统采用springboot框架(MVC模式开发) ,系统具有完整的源代码和数…

多域名证书

多域名证书是一种可以保护多个不同域名的SSL证书,最多可保护250个域名。与单域名证书相比,多域名证书具有更多的优势,比如可以更好地管理多个域名,减少部署证书的次数,提高网站安全性等。多域名证书有三种验证方式可以…

mac电脑安装雷蛇管理软件,实现调整鼠标dpi,移动速度,灯光等

雷蛇官网只给了win版本驱动 mac版本驱动到这里下载: GitHub - 1kc/razer-macos: Color effects manager for Razer devices for macOS. Supports High Sierra (10.13) to Monterey (12.0). Made by the community, based on openrazer. 安装后会显示开发者不明,请丢弃到垃圾桶.…

单片机综合小项目

一、单片机做项目常识 1.行业常识 2.方案选型 3.此项目定位和思路 二、单片机的小项目介绍 1.项目名称:基于51单片机的温度报警器 (1)主控:stc51; (2)编程语言:C语言 (…

00TD时尚儿童穿搭,这件小熊毛衣太好看了吧

寒冷的秋冬季怎么少的了毛衣呢 软糯亲肤又时尚百搭的款谁不爱 除了纯色还有条纹设计 可爱小熊图案可爱又吸睛 经典时尚的款怎么穿都好看哦!

css 特别样式记录

一、 这段代码神奇的地方在于, 本来容器的宽度只有1200px,如果不给img赋予宽度100%,那么图片 会超出盒子,如果给了img赋予了宽度100%,多个图片会根据自己图片大小的比例,去分完那1200px,如图二。…

Netty P1 NIO 基础,网络编程

Netty P1 NIO 基础,网络编程 教程地址:https://www.bilibili.com/video/BV1py4y1E7oA https://nyimac.gitee.io/2021/04/25/Netty%E5%9F%BA%E7%A1%80/ 1. 三大组件 1.1 Channel & Buffer Channel 类似 Stream,它是读写数据的双向通道…

华为9.20笔试 复现

第一题 丢失报文的位置 思路&#xff1a;从数组最小索引开始遍历 #include <iostream> #include <vector> using namespace std; // 求最小索引值 int getMinIdx(vector<int> &arr) {int minidx 0;for (int i 0; i < arr.size(); i){if (arr[i] …