当前位置: 首页 > Web前端 > JavaScript

Nydus图像扫描加速

时间:2023-03-27 10:04:27 JavaScript

文章|余硕,上海交通大学22届毕业生,阿里云开发工程师,从事云原生底层系统的开发与探索。本文6369字阅读16分钟GitLink编程夏令营是CCF中国计算机学会指导下,由CCF开源开发委员会(CCFODC)组织的面向全国大学生的暑期编程活动。这是余硕对今年夏令营参加Nydus开源项目的总结。主要介绍Nydus在支持镜像扫描修复方面所做的研究和相关工作。部分。1题目背景Nydus开源镜像加速框架Nydus是CNCF孵化项目Dragonfly的子项目,提供容器镜像和按需加载代码包的能力。应用Nydus时,无需等待所有数据下载完成再启动服务。Nydus支持在生产环境中每天创建数百万个加速镜像容器。与OCIv1格式相比,在容器启动性能、镜像空间占用、网络带宽效率、端到端数据一致性等方面具有很大优势,可扩展到其他数据分发场景,如延迟加载NPM包。Nydus目前由蚂蚁集团、阿里云和字节跳动联合开发。Containerd和Podman社区已经接受了Nydus运行时作为他们的社区子项目,它也是KataContainers和Linuxv5.19内核原生支持的图像加速解决方案。关于Nydus镜像加速开源项目的详细介绍,可以参考:Nydus——下一代容器镜像的探索实践。项目描述添加一个用于扫描和修复坑道镜像的命令行工具,包括以下功能:提供坑道镜像url和需要替换的文件列表;使用工具拉取镜像Bootstrap;在镜像中找到对应的文件并替换;将其打包成新的并将其上传回注册表。一言以蔽之,最初项目的目标是实现一个扫描和修复虫道图像的命令行工具,而这些功能就是这个工具或工具组的实现过程。不过这个项目还是有些实验性的,核心是为Nydus格式的图片提供扫描修复功能或指引。如果有更好的方法,项目不一定要按照原来的项目描述来实施。因此,在完成下一个项目的过程中,我们首先对现有的图像扫描/修复工具和服务进行了研究,以确定项目的最终形式。图像扫描工具和服务扫描和修复镜像扫描和修复可以分为两个过程。扫描不改变原始图像内容,只需要找出扫描目标是否存在某种缺陷;图片修复需要根据缺陷对图片进行修改,包括但不限于图片内容、图片层次组织等。我们研究发现,目前主流的开源图片扫描引擎,包括云厂商图片安全服务,只涉及图片扫描功能,不会主动添加图像修复功能。我们分析的主要原因有:直接镜像修复可能会引入新的安全问题;图像扫描内容种类繁多,很可能需要针对不同类型的图像安全问题设计不同的修复方式;图像修复功能可以通过替换重新封装。因此,镜像安全服务暂时只提供扫描结果的安全报告,具体修复操作由用户自行决定。我们也打算按照这样的思路:在这个项目中,实现对镜像的安全扫描功能,并提供一份报告,作为用户镜像修复的参考。我们也探索和讨论了对镜像修复的支持,或者在镜像修复场景下Nydus特性的增强,比如镜像包替换后的去重和重组等,或许这些在未来的Nydus中可以加入特性。镜像扫描介绍了镜像扫描的原因和内容。容器镜像是当前容器/软件分发的基础,包括容器隔离环境和软件执行环境的相关内容。因此,确保其安全性非常重要。图片扫描就是扫描图片中的所有内容,及时发现可能存在的安全漏洞或隐私泄露。一般来说,图片扫描需要注意图片的安全性和健壮性。扫描的内容主要分为三类:1.安全漏洞。包括系统软件包和应用软件库中可能存在的安全漏洞。通过将镜像中这些库/软件包的来源和版本与CVE数据库中报告的包的来源和版本进行比较,可以定位可能存在的安全漏洞。2.配置。包括镜像运行的环境配置以及镜像中相关内容的组合可能带来的问题。帮助尽早定位配置错误以及配置错误可能带来的安全风险。3.隐私。需要扫描的是用户指定的一些隐私信息。例如,用户不小心将密钥等信息保存到图像中。如果在扫描配置中指定,扫描过程可能会发现这些隐私信息,避免隐私泄露和可能的安全问题。扫描引擎常见的扫描引擎有Trivy、Synk等,Docker官方使用的是Synk,但商业化程度更高;Trivy是一个开放性较好的CNCF项目。如何使用镜像扫描在我们的研究中,镜像扫描主要有以下三种应用方式:1.基本使用。镜像扫描过程可以直接由集成镜像扫描引擎的容器运行时触发,也可以由镜像扫描引擎命令行触发。例如运行$dockerscanimage-url扫描图片并输出相应的报告。来源:https://docs.docker.com/engine/scan/2。流程整合。图像扫描过程可以集成到图像中心或CI/CD过程中。例如,将图片扫描集成到数据中心,每次上传图片到数据中心都会触发图片扫描,可以保证从数据中心下载的图片始终安全扫描;集成在CI/CD流程中,设置触发条件可以保证镜像在镜像生成、镜像部署等过程中使用的镜像的安全。来源:https://www.containiq.com/post/container-image-scanning3。扫描服务。云厂商提供镜像安全服务。它们可能是基于前两种使用方法来实现的,但也有很多功能上的增强。想要使用图片扫描功能的用户,也可以直接购买类似的安全服务,灵活配置。来源:https://cloud.google.com/container-analysis/docs/on-demand-scanning-howtoPART。2问题解决的基本思路也可以复用已有的图像扫描引擎,实现对Nydus端的对接支持,从而完成Nydus图像扫描的功能实现。我们最终选择了结合现有图片扫描引擎的实现思路。虽然为Nydus实现专用的图像扫描工具可以更好地利用Nydus的特性,但这并不是考虑图像功能生态的好方法。重复使用或集成到现有图像扫描工具中。一方面,您可以直接使用已实现的图像扫描引擎的全面内容扫描功能;另一方面,无需重写相关接口即可与上层图像安全服务对接。这样也可以减少一些功能定制,减轻用户的负担。因此,本项目选择后一种实现的基本思路。扫描思路:FileSystemvsImageTrivy实现扫描功能的框架1.控制路径。Trivy在镜像扫描上由以下路径控制,每触发一个命令,就会由一个Scanner控制。关键是工件和驱动程序。扫描引擎一般支持多种格式的扫描,如OCIv1镜像或rootfs镜像,一般支持本地或远程存储信息等,这些一般可以通过ScannerConfig配置或自动解析。atifact存储图像(包括文件系统)元数据,如果内容已经被扫描过,它还可以存储部分解析信息。另外,本地加载的CVE数据也可以通过Artifact获取。Driver中的Scan方法表示在特定扫描期间应用的检查方法。2.关键动作。local.ScannerApplierTrivy中的LocalScanner就是上面提到的本地扫描的控制结构。可以看出Scanner中定义的行为是ApplyLayer。也就是说,图像将被逐层扫描。Applier保存了Artifact信息,Artifact信息是一个链接特定扫描方式和存储信息的结构。3.分析图像。以上两个流程了解了整体的Scan流程控制,以及对图片的具体扫描方式。与镜像相关的另一个关键过程是如何有针对性地分析和扫描镜像信息。这个过程是在Artifact中实现的。ArtifactWalker-AnalyzerArtifact有图像元信息,还有用于存储和分析图像信息的Cache。主要要考虑的是Trivy目前支持的不同类型图像的不同设置。另一个关键是分析器。Analyzer对应图像分层的操作。不同类型的镜像操作不同。例如对于OCIv1镜像,可能是每一层镜像拉取的完整数据流进行分析。对于FileSystem来说,就是文件树的层次遍历。方案选择在了解了Trivy的实现后,我们发现直接将Nydus打包成类似OCIv1的镜像进行扫描并不合适。Nydus镜像内容的层级组织发生了变化,并且还具有按需加载的特性。如果直接拉取,不一定保证拉取信息的完整性,而且如果要完全支持镜像的拉取,就会失去Nydus的特性。因此,我们最终选择了优先扩展坑道在FSArtifact模式下的影像扫描能力。相关命令是:$trivyimagenydus-image-url?$trivyfs/path/to/nydus_imgae_mountpoint?这样做的好处是可以利用Nydus的按需加载功能。我们发现很多软件包的扫描不需要下载完整的文件内容。在很多情况下,可以判断出一些部分信息甚至是元信息。此功能可以利用Nydus的按需加载来加速整个图像扫描过程。其次,特殊格式的镜像会有挂载文件系统的操作。这种方法可以扩展到更多特殊格式的图像。本项目最终以工具的形式为Nydus集成了加速镜像文件系统挂载的能力,可以适配主流的镜像扫描框架。未来可以考虑对社区镜像扫描解决方案做更深层次的整合,比如Trivy、Clair、AnchoreEngine等,支持直接指定Nydus镜像Reference进行扫描,优化端到端的用户体验。该解决方案支持在Nydus端进行图像扫描。简单的命令过程是:$nydusifyviewlocalhost:5000/ubuntu:latest-nydus/path/to/root_path[比容器简单,直接获取文件树]$trivyfs/path/to/rootpathNydusify是一个镜像Nydus提供的转换、验证和镜像文件系统挂载工具。使用方法请参考:https://github.com/dragonflyoss/image-service/blob/master/docs/nydusify.md。Nydusify中实现的上述核心功能是由FileSystemViewer结构体控制的:需要保存在该结构体中的成员变量,具有本进程的一些输入信息和配置信息。SourceParser用于解析镜像url。MountPath是可以指定挂载文件系统的地址。NydusdConfig是NydusDaemon在Mount进程中的配置。image-url是必需的输入。View()是调用方法。调用nydusify视图时,主要分为三个步骤:解析image-url;根据解析信息拉取文件系统元数据Bootstrap;根据Bootstrap,Nydusd将文件系统挂载到指定路径。后面调用trivyfs时,可能会出现分层遍历挂载文件系统的情况;当镜像挂载点的文件被打开时,会触发FUSE请求给NydusDaemon(Nydusd),Nydusd会按需从远程镜像中心拉取该文件的Chunk数据提供给扫描引擎分析文件内容。部分。3TopicDemonstrationDemo说明我们实现了这个功能,比如demo中的演示:性能测试我们在Ubuntu、Wordpress、Tensorflow等镜像上进行了测试。测试结果如下:以扫描延迟为衡量标准,可以看出Nydus的安全扫描时间明显少于OCIv1基础镜像。优化程度与镜像文件系统的复杂程度、测试网络环境等因素有关。我们也从实际的图片扫描场景中了解到,当安全问题经常出现时,比如一些0day漏洞,我们需要检测少量的特定文件元数据或者大量图片上的数据。这种情况更能体现Nydus镜像懒加载的优势,安全扫描速度可以得到很大的提升。当然,Trivy对OCIv1图像的扫描优化会影响比较结果。我们的TrivyImage对同一张图片进行多次扫描,可以得到如下结果:可以看出多次扫描后花费的时间延迟减少了。如前所述,扫描信息匹配将存储在本地缓存中。这将基于BlobID作为键进行存储。因此,Trivy在扫描同一张图片时可以直接查询Cache,而无需反复拉取图片形成优化。我们也想在未来集成类似的优化,这就是为什么我们也想在未来促进扫描引擎社区更好的支持。部分。4话题扩展说明Nydus除了扫描镜像内容的安全性外,本身还提供了命令工具nydus-imageinspect来检查Nydus镜像。nydus-imageinspect命令可以通过检索Nydus图像中包含的文件系统元数据信息来查看Nydus图像的组织。此外,还可以判断坑道图像是否损坏。随着Nydus的发展,它对文件系统布局的支持也从v5扩展到了v6。RAFSv6兼容EROFS,从而进一步提升性能。nydus-imageinspect是在RAFSv5中设计的,扩展到RAFSv6后,扩展了一些子命令以实现兼容性。但是这样的扩展是针对v5/v6单独写的,即需要执行子命令时,还需要对文件系统格式进行判断。此外,还有一些子命令没有兼容性扩展。这种不完善的支持存在一定的遗留问题,功能不完整、不统一。这样的代码组织也失去了易读性,不利于后续的维护,在不同RAFS格式相关的功能迭代升级时也比较容易出问题。事实上,Nydus已经为这两种格式的文件系统元数据实现了统一的API接口。比如RafsSuperInodes、RafsSuperBlock等结构体有统一的获取信息的方法,屏蔽了不同的底层实现。因此,在此基础上,需要对nydus-imageinspect命令的相关功能进行重构。在原有架构的实现中,有一个Executor结构,根据子命令来决定具体调用哪个方法。例如,当Executor收到子命令stats时,会调用cmd_stats函数,执行并完成结果的输出显示。我们需要重构的是每个子命令调用的方法,上层调用逻辑不变。具体的子命令方法有:cmd_statscmd_list_dircmd_change_dircmd_stat_filecmd_list_blobscmd_list_prefetchcmd_show_chunkcmd_check_inode此处,各子命令调用方法的修改这里不再详述。一般的做法是使用RAFSmod中统一的API来实现所有原有的功能逻辑。测试我们实施了两个测试。两次测试的目的都是为了保持重构前后功能实现的一致性。测试一:以交互形式比较输出结果。这是一个功能测试。针对每条指令的每一种可能情况,选取具有代表性的图片进行测试对比。测试2:集成烟雾测试。这是冒烟测试。nydus-imageinspect命令和请求模式可以将子命令的输出序列化为json格式的结果。我们将原始代码的结果序列化成json格式作为参考输出,然后与重构代码的输出结果进行对比。所选图像是Nydus存储库中用于烟雾测试的图像。这部分测试也集成在了Nydus仓库中,也可以保证这个功能的正确性在以后的CI中没有被破坏。结果提示ModeStatslsCdStatFileBlobsPrefetchChunkOffsetIcheckIndexRequestModeStatsPrefetchBlobsPART。5收益及预期收益非常荣幸参与本项目的开发,同时对项目组织老师赵鑫、项目指导助理姚银南、严松以及虫道社区表示衷心的感谢。通过本项目的开发,收获颇丰:知识方面,回顾并加深了对文件系统的理解,学习了容器镜像格式的组织,第一次尝试了Go语言开发,开始了了解软件测试;在技??能方面,锻炼了协调时间、公开讨论、问题定位的能力。更重要的是,我认为参与这个项目让我增长了对容器场景应用的认识,提高了我设计完整的解决方案和系统的能力。当然,最大的好处大概就是愉快的体验吧!我体会到了开源合作的快乐,开源价值的快乐。期待这个项目,主要是为Nydus增加对图片扫描功能的支持,以及重构Nydus的Inspect分析工具。如上所述,我们将继续探索Nydus图像扫描如何融入扫描引擎,图像扫描和修复的优化也值得探索。关于Nydus镜像格式细节、userland文件系统、EROFS等,我还有很多需要学习的地方,希望自己能一直参与社区,不断丰富自己的容器存储知识,同时为社区做出更大的贡献.了解更多...NydusStar?:https://github.com/dragonflyoss/image-service本周推荐阅读Nydus——下一代容器镜像探索与实践基础Dragonfly与NydusMirror模式整合实践