Nydus
资料
特点
- 镜像lazy加载,按需下载镜像blob数据,容器启动速度更快;
- blobs级别的镜像数据去重,节省空间;
- 提供用户态文件系统Fuse,兼容OCI分发标准,和artifacts标准(lazy加载就是基于该fuse实现);
- 支持镜像存储backend,镜像数据可以放registry或对象存储上;
- 与Dragonfly P2P系统集成;
架构
- 主要包括一种新的镜像格式和一个负责解析容器镜像的FUSE用户态文件系统进程;
- nydus可以配置一个本地缓存(local cache)用来缓存镜像数据,避免每次都从远端数据源拉取数据;
nydus Rafs vs OCIv1镜像格式
- 如下图所示,Rafs镜像格式是分了两块:元数据(bootstrap)、镜像数据块(blobs);
- OCI下的镜像层文件tar.gz变成了只存储文件数据块,文件以chunk为粒度进行切割和去重;
Rafs用户态FUSE缺陷和解决
- 用户太的FUSE会存在大量的系统开销,当容器中存在大量文件时,会产生大量的fuse请求,生成内核态和用户态之间的频繁切换,造成性能瓶颈;
- nydus为了解决该问题,在开发Rafs v6镜像格式,该功能依托于EROFS文件系统,用于实现真正的内核态的容器镜像格式;
- 该Rafs v6的按需加载技术,将由EROFS over Fscache技术完成,阿里为此改造了linux fscache文件的缓存内核模块,以于合并到linux 5.19内核版本主线;
fscache是linux系统中成熟的文件缓存方案,广泛用于网络文件系统,如NFS, Ceph等,阿里对该模块进行了增强,使用支持本地文件系统(如erofs)的按需加载特性,因此该方案中,fscache接管了本地缓存管理的工作(即前面的local cache);
- 改造后的视图变为:
- 下图为pod使用fscache与nydus交互的过程:
- 官方使用教程:https://github.com/dragonflyoss/nydus/blob/master/docs/nydus-fscache.md
Rafs镜像格式
Rafs: Registry Acceleration File System
Merkle Tree
- nydus实现了一种新的镜像格式(docker原生的OCI镜像格式可以参考我之前的文章”OCI镜像规范”),该格式是将镜像文件拆分成元数据和数据blobs两层,其中的元数据就是一颗以文件/目录为树节点的Merkle Tree;
- 该数据结构的特点有:
- MT树可以是二叉树也可以为多叉树,这里nydus是后者;
- MT树叶子节点的value是数据集合的单元数据或单元数据的HASH;
- MT树的非叶子节点的value是根据所有子节点的值计算出来的HASH值;
- 该数据结构的优势有:
- 对比两颗MT的root节点能直接对比出该树的数据是否一样,如这里的nydus可以通过root的HASH值直接判断出下载的镜像是否与原始镜像一样;
- 如数据不一样,能够快速分辨出哪一个子节点不同,递归后即可快速找出异常的叶子节点,因此可以仅重新下载该叶子节点的数据即可;
- blobs的HASH列表可以看成一颗调度为2的MT树;
- 检索数据块的时间复杂度为
Log(N)
- 该数据结构被广泛应用于P2P网络中,用于确保从其它节点接受的数据没有损坏或被人为替换;
nydus镜像元数据
- 如下图所示,nydus的元数据是以文件/目录为节点组件的MT树,所有叶子节点为文件,value由文件内容的HASH决定,非叶子节点为目录,HASH由目录下的子节点HASH确定:
nydus blobs镜像数据
- 镜像数据是被分成固定大小的blobs数据块,大小为4MB;
- blobs可以用于多镜像共享;
- 传统OCI镜像是以gzip从仓库拉到本地并进行解压的,解压前会有数据校验,但解压后并不会再进行校验,这里可能就存在漏洞,而nydus的数据不需要解压到本地,且对每一次数据访问均会进行校验,因此提供了blobs级的安全校验;
对比
- 如下图,是官方给出的nydus与之前的镜像加速方案的对比图,如Slacker, dragonfly方案: