共计 6884 个字符,预计需要花费 18 分钟才能阅读完成。
文|余硕
上海交通大学 22 届毕业生阿里云开发工程师
从事云原生底层零碎的开发和摸索工作。
本文 6369 字 浏览 16 分钟
GitLink 编程夏令营是在 CCF 中国计算机学会领导下,由 CCF 开源倒退委员会(CCF ODC)举办的面向全国高校学生的暑期编程流动。
这是往年的夏令营流动中,余硕同学加入 Nydus 开源我的项目的总结,次要介绍了 Nydus 为反对镜像扫描与修复所做的钻研与相干工作。
PART. 1 课题背景
Nydus 开源镜像减速框架
Nydus 是 CNCF 孵化我的项目 Dragonfly 的子项目,它提供了容器镜像,代码包按需加载的能力。Nydus 利用时无需期待全副数据下载实现便可开始服务。
Nydus 在生产环境中曾经撑持了每日百万级别的减速镜像容器创立。它在容器启动性能、镜像空间占用、网络带宽效率、端到端数据一致性等方面相比 OCI v1 格局有着微小劣势,并可扩大至其它数据散发场景,比方 NPM 包懒加载等。
目前 Nydus 由蚂蚁团体、阿里云、字节跳动联合开发。Containerd、Podman 社区曾经承受了 Nydus 运行时作为其社区子项目,它也是 Kata Containers 以及 Linux v5.19 内核态原生反对的镜像减速计划。
无关 Nydus 镜像减速开源我的项目的具体介绍,能够参考:Nydus——下一代容器镜像的摸索实际。
我的项目形容
为 Nydus 镜像减少一个扫描和修复的命令行工具,蕴含以下性能:
- 提供一个 Nydus 镜像 url 和须要替换的文件列表;
- 应用工具拉取镜像 Bootstrap;
- 找到镜像中对应的文件并替换;
- 打包成新的镜像并上传回 Registry。
概括来说,原有我的项目指标是为 Nydus 镜像实现一个扫描和修复的命令行工具,其中这些性能是这个工具或者工具组的实现流程。
但此我的项目具备肯定的实验性,其外围是为 Nydus 格局的镜像提供扫描和修复的性能或者指引。如果存在更好的形式,我的项目最终不肯定要依照原有我的项目形容去实现。因而在接下来的课题实现过程中,咱们首先对已有镜像扫描 / 修复的工具与服务进行了调研,来确定此课题计划的最终状态。
镜像扫描工具及服务
扫描和修复
镜像扫描和修复能够被拆解为两个过程。扫描不更改原有的镜像内容,只须要寻找扫描指标是否存在某种缺点;镜像修复则须要依据缺点改变镜像,包含但不限于镜像内容,镜像层级组织等。咱们调研发现,以后支流开源镜像扫描引擎包含云厂商镜像平安服务都只波及镜像扫描的性能,不会被动增加镜像修复的性能。
咱们剖析次要的起因有:
- 间接进行镜像修复可能引入新的平安问题;
- 镜像扫描的内容存在不同品种,很可能须要为不同品种的镜像平安问题设计不同的修复形式;
- 镜像修复性能能够通过从新打包镜像代替。
所以,镜像平安服务临时只是提供扫描后果的平安报告,具体的修复操作由用户自行决定。咱们也筹备沿用这样的思路:在本课题中,为镜像实现平安扫描的性能,并提供报告作为用户镜像修复的参考根据。
咱们也摸索探讨了镜像修复的反对,或者 Nydus 个性在镜像修复场景下的加强,比方镜像内包替换后的去重与重组等,或者这些能够是将来 Nydus 中减少的性能个性。
镜像扫描介绍
镜像扫描的起因与内容
容器镜像是以后容器 / 软件散发的根底,外面蕴含了容器隔离环境以及软件执行环境的相干内容。因而保障其安全性变得非常重要。镜像扫描即是要扫描镜像中的所有内容,及时发现可能蕴含的安全漏洞或者隐衷泄露。
综合来看,镜像扫描须要关注镜像的安全性与健壮性,扫描的内容次要分为三类:
1. 安全漏洞。 包含零碎软件包和应用软件库中可能存在的安全漏洞。能够通过比对镜像中这些库 / 软件包的起源、版本等与 CVE 数据库中报告的破绽的包的起源、版本来定位可能存在的安全漏洞。
2. 配置。 包含镜像运行的环境配置和镜像中相干内容组合可能带来的问题。帮忙尽早定位配置谬误以及配置谬误可能带来的平安危险。
3. 隐衷。 须要扫描的是用户指定的一些隐衷信息。比方用户不小心将密钥等信息存入镜像。如果在扫描配置中进行指定,扫描过程可能发现这些隐衷信息,防止隐衷泄露以及可能带来的平安问题。
扫描引擎
常见的扫描引擎有 Trivy、Synk 等。Docker 官网应用的是 Synk,但它比拟商业化;Trivy 是 CNCF 的我的项目,开放性较好。
镜像扫描的应用形式
在咱们的调研中,镜像扫描次要利用形式有三种:
1. 根底应用。 镜像扫描的过程能够间接通过集成了镜像扫描引擎的容器运行时或者镜像扫描引擎命令行触发。比方运行 $ docker scan image-url
,能够扫描镜像,并输入相应的报告。
source:https://docs.docker.com/engine/scan/
2. 流程集成。 镜像扫描的过程能够集成到镜像核心或者 CI/CD 流程中。比方将镜像扫描集成到数据中心,在每次镜像上传到数据中心时触发镜像扫描,能够保障从数据中心下载的镜像总是通过平安扫描的;集成在 CI/CD 流程中,设置触发条件,能够保障镜像生成,镜像部署等过程所应用的镜像的安全性。
source: https://www.containiq.com/post/container-image-scanning
3. 扫描服务。 云厂商提供了镜像平安的服务。它们背地可能是基于前两种应用形式实现,然而还能够有很多种性能的加强。用户想应用镜像扫描的性能也能够间接购买相似的平安服务,并进行灵便的配置。
source: https://cloud.google.com/container-analysis/docs/on-demand-scanning-howto
PART. 2 课题解决思路
基本思路
课题首先要解决的基本思路是,如我的项目形容个别为 Nydus 实现一个专属的镜像扫描工具;还是复用已有的镜像扫描引擎,在 Nydus 侧实现对接反对,从而实现 Nydus 镜像扫描的性能实现。
咱们最终抉择了联合已有镜像扫描引擎的实现思路。只管为 Nydus 实现一个专属的镜像扫描工具能够更好的利用 Nydus 的个性,然而从镜像性能生态上思考,这并不是一个很好的形式。复用或者集成到现有的镜像扫描工具,一方面能够间接应用已实现的镜像扫描引擎中全面的内容扫描能力;另一方面,与下层镜像平安服务的对接也不必再重写相干接口。这样也能够缩小一些性能定制,缩小用户应用的累赘。因而此课题抉择了后一种实现的基本思路。
扫描思路:FileSystem vs Image
Trivy 扫描性能实现的框架
1. 管制门路。
Trivy 在镜像扫描上由以下门路管制,每触发一次命令,会由一个 Scanner 管制。其中要害的是 artifact
和 driver
。扫描引擎个别能够反对多种格局的扫描,比方 OCI v1 镜像或者镜像 Rootfs,同时个别也反对本地或者远端存储信息等。这些个别可由 ScannerConfig
配置或者主动解析。
atifact
存储着镜像 (包含文件系统) 元信息,如果曾经扫描过其中的内容,还能够存储局部解析后的信息。另外,load 到本地的 CVE 数据等也可通过 Artifact 获取。Driver 里的 Scan 办法示意的则是利用在特定扫描过程中的查看办法。
2. 要害动作。
- local.Scanner
- Applier
Trivy 中 Local Scanner 是前文提到的本地进行扫描的控制结构。能够看出 Scanner 里定义的行为是 Apply Layer。也就是将对镜像逐层进行扫描。Applier 保留了 Artifact 信息,是分割具体扫描办法和存储信息的构造体。
3. 解析镜像。
上述两个过程了解了总体 Scan 的过程管制,以及具体针对镜像的扫描办法。与镜像相干的还有一个要害过程是如何针对性的解析扫描镜像信息。这一过程实现在 Artifact 中。
- Artifact
- Walker-Analyzer
Artifact 中有镜像元信息,还有保留解析镜像信息的 Cache 等。次要要思考的是以后 Trivy 反对的不同品种镜像而进行不同的设置。
另一要害的是 Analyzer。Analyzer 对应的是镜像分层的操作。对不同品种的镜像操作不同。比方对于 OCI v1 的镜像,可能就是每层镜像拉取的残缺数据流进行剖析。对于 FileSystem,就是档次遍历文件树。
计划抉择
理解了 Trivy 的实现后,咱们发现间接把 Nydus 打包成 OCI v1 相似的镜像去扫描并不适合。Nydus 镜像内容中档次组织曾经产生了变动,也具备按需加载的特点。若间接拉取,不肯定保障拉取信息的齐备,想要齐备反对镜像的拉取也会失落 Nydus 的个性。
因而咱们最终抉择在 FS Artifact 形式下优先拓展 Nydus 的镜像扫描能力。
相干的指令是:
$trivy image nydus-image-url ✗
$trivy fs /path/to/nydus_imgae_mountpoint ✓
这样做的益处一是能够利用 Nydus 按需加载的个性。咱们发现对于很多软件包的扫描并不需要残缺的文件内容的下载,很多时候一些部分信息甚至元信息即可判断。这一特点能够利用上 Nydus 的按需加载,从而放慢整个镜像扫描的过程。二是非凡格局的镜像都会有挂载文件系统这一操作。这样的形式能够推广到更多的非凡格局镜像。
本课题最终是以工具模式为 Nydus 集成了减速镜像文件零碎挂载的能力,这可能适配支流的镜像扫描框架,将来咱们能够思考为社区镜像扫描计划做更深度的集成,比方 Trivy、Clair、Anchore Engine 等,反对间接指定 Nydus 镜像 Reference 做扫描,优化端到端的用户体验。
计划实现
在 Nydus 侧提供镜像扫描的反对,简略指令过程为:
$ nydusify view localhost:5000/ubuntu:latest-nydus
/path/to/root_path
[比起容器简略,间接拿到文件树]
$ trivy fs /path/to/rootpath
Nydusify 是 Nydus 提供的镜像转换,校验与镜像文件零碎挂载工具,应用形式能够参考:https://github.com/dragonflyoss/image-service/blob/master/docs/nydusify.md。
下面实现在 Nydusify 中的外围性能由 FileSystemViewer
构造体管制:
此构造体须要保留的成员变量有此过程的一些输出信息和配置信息。SourceParser
用于解析镜像 url。MountPath
是能够指定的文件系统 Mount 的地址。NydusdConfig
是 Mount 过程 Nydus Daemon 的配置。image-url
是必须提供的输出信息。View()
是调用办法。
当 nydusify view
被调用时,次要将产生三个步骤:
- 解析
image-url
; - 依据解析信息,拉取文件系统元数据 Bootstrap;
- 依据 Bootstrap,Nydusd Mount 文件系统到指定门路。
之后 trivy fs
被调用时,可能产生:
- 档次遍历挂载的文件系统;
- 关上镜像挂载点中某个文件时,会触发 FUSE 申请到 Nydus Daemon (Nydusd),Nydusd 会从远端镜像核心按需拉取文件的 Chunk 数据,以提供给扫描引擎剖析文件内容。
PART. 3 课题展现
Demo 展现
咱们实现了这一性能,如 demo 中演示:
性能测试
咱们在 Ubuntu、Wordpress、Tensorflow 等镜像上进行了测试。
测试后果如下:
以扫描时延作为衡量标准,能够看出 Nydus 的平安扫描时间要显著少于根本 OCI v1 镜像。这其中优化的幅度与镜像文件零碎复杂程度,测试网络环境等因素无关。
咱们还从理论镜像扫描场景理解到,很多时候呈现平安问题时,例如一些 0day 破绽,咱们须要对大批量镜像进行特定的大量文件元数据或数据的侦测。这种状况就更能体现出 Nydus 镜像懒加载的劣势,平安扫描速度可能大幅度提高。
当然,Trivy 对 OCI v1 镜像的扫描优化会影响比照后果。咱们 Trivy Image 屡次对同一镜像进行扫描,可失去上面的后果:
能够看出,屡次扫描之后破费的时延降落。如之前提到,扫描信息匹配会存到 local Cache 中。这是会依据 Blob ID 做为 key 来存储的。因而 Trivy 在扫描同一镜像时能够间接去查问 Cache 而不用反复拉取镜像造成优化。咱们在将来也想集成相似的优化,这也是之后咱们也想在扫描引擎社区推动更好的反对的起因。
PART. 4 课题拓展
形容
除了扫描镜像内容的安全性,Nydus 自身提供了指令工具 nydus-image inspect
对 Nydus 镜像进行查看。nydus-image inspect
指令通过检索 Nydus 镜像中蕴含的文件系统元数据信息,能够查看 Nydus 镜像的组织状况。进一步能够判断 Nydus 镜像是否损坏等。
随着 Nydus 的倒退,它反对文件系统 Layout 也从 v5 扩大到 v6。RAFS v6 能够兼容 EROFS,由此取得性能上的进一步晋升。nydus-image inspect
在 RAFS v5 时曾经设计,扩大到 RAFS v6 之后,一些子命令为了兼容进行了扩大。然而这样的扩大是为 v5/v6 离开写成的,也就是须要执行子命令时还须要对文件系统格局进行一次判断。
此外,还有一些子命令没有做到兼容性扩大。这样的不齐全反对存在肯定的遗留问题,没有做到性能的齐备和对立。这样的代码组织也损失了易读性,不利于后续的保护,不同 RAFS 格局相干性能的迭代降级中也比拟容易产生问题。
事实上,Nydus 曾经为这两种格局的文件系统元数据实现了对立的 API 接口。
比方对 RafsSuperInodes
, RafsSuperBlock
等构造有对立的办法进行信息的获取,对不同的底层实现进行了屏蔽。因而在此基础之上,有必要对 nydus-image inspect
指令的相干性能进行一次重构。
实现
原有的架构中,存在一个 Executor
构造依据子命令判断调用哪一个具体的办法。比方 Executor
收到子命令 stats 时会调用 cmd_stats 函数,执行并实现后果的输入显示。
咱们须要重构的是针对每一条子命令所调用的办法,下层的调用逻辑放弃不变,具体而言子命令办法有:
- cmd_stats
- cmd_list_dir
- cmd_change_dir
- cmd_stat_file
- cmd_list_blobs
- cmd_list_prefetch
- cmd_show_chunk
- cmd_check_inode
这里不再对每一条子命令调用办法的批改进行详细描述。大略做法是应用 RAFS mod 中对立的 API 实现所有本来的性能逻辑。
测试
咱们实现了两种测试。两种测试的目标都是为了放弃重构前后性能实现的统一。
测试一: 交互模式比对输入后果。
这是一种功能测试。针对每条指令每种可能呈现的状况,选取代表性镜像进行测试与比对。
测试二: 集成冒烟测试。
这是一项冒烟测试。nydus-image inspect
命令还有 request mode
能够将一条子命令的输入序列化成 json 格局的后果。咱们将原有代码的后果序列化成 json 格局作为参考输入,再将重构后代码的输入与之一一比对。选取的镜像为 Nydus 仓库中用于冒烟测试的镜像。这一部分的测试也集成在 Nydus 仓库中,在当前的 CI 里也能够保障这项性能的正确性没被毁坏。
成绩
Prompt Mode
Stats
ls
Cd
Stat File
Blobs
Prefetch
Chunk Offset
Icheck Index
Request Mode
Stats
Prefetch
Blobs
PART. 5 收益与瞻望
收益
我十分荣幸能加入这次我的项目的开发,也要向我的项目组织老师赵新、我的项目领导助理姚胤楠、严松老师以及 Nydus 社区示意衷心的感激。
通过这次我的项目的开发,我播种了许多:常识上,我温习并更深刻理解了文件系统,学习了容器镜像格局的组织,还首次尝试了 Go 语言开发,也开始理解软件测试;技能上,我锤炼了协调工夫,凋谢探讨,问题定位的能力。
更重要的是,我认为参加这次我的项目减少了我对容器场景利用的见识,也晋升残缺解决方案与零碎设计的能力。当然,可能最大的收益是播种了一次高兴的体验!领会了开源单干的高兴,也领会到了开源价值产生的高兴。
瞻望
此次我的项目次要是为 Nydus 增加了镜像扫描性能的反对,另外重构了 Nydus 的 Inspect 剖析工具。如前文所说,后续还要持续摸索 Nydus 镜像扫描集成到扫描引擎的形式, 镜像扫描和修复的优化也值得摸索。对于 Nydus 镜像格局细节,用户态文件系统,EROFS 等,我还有很多须要学习。
心愿能始终参加社区,不断丰富本人容器存储方面的常识,同时也能为社区做出更大的奉献。
理解更多 …
Nydus Star 一下✨:
https://github.com/dragonflyoss/image-service
本周举荐浏览
Nydus —— 下一代容器镜像的摸索实际
Nydus 镜像减速插件迁入 Containerd 旗下
Nydus | 容器镜像根底
Dragonfly 和 Nydus Mirror 模式集成实际