1、背景和动机
随着云原生(Cloud Native)被工业界广泛接受,容器(container)在数据中心被广泛部署,其地位正在逐步取代传统的虚拟机(Virtual Machine)。当然目前依然存在用轻量虚拟机来运行和部署容器,比如使用Kata Containers。简单来讲, 容器化是将程序的代码以及相关的软件库(包括对操作系统依赖库等)打包在一起, 创建可在任意基础架构上一直运行的轻量级执行文件(容器)。容器通常以镜像(image)的形式进行发布,一般用户可以直接通过一些轻量级容器运行工具,比如containerd,docker等进行运行。更高级一些,用户可以通过K8S (Kubernetes)这样的开源系统,进行容器的自动部署,扩展和管理。
随着容器技术的广泛普及,用户对容器技术的优化需求也越来越高。比如大规模部署容器的时候,客户希望能够在非常短的时间内启动容器。举个实际的应用场景,FaaS (Function as a service)目前也会采用容器的方式进行部署和扩展。一般来讲,如果使用容器来部署FaaS,可以采用以下的几个步骤:
根据用户的需求,将所要执行的函数,进行编译生成二进制文件,将可执行二进制文件与所需的库打包到文件系统,并且生成相应的镜像。
镜像被调度到某个节点, 尽快准备好容器执行环境,包括将container的镜像解包到文件系统中。
启动容器(包括计算,网络环境以及文件系统),然后在选定的容器中执行 FaaS 应用程序。
对于FaaS这样的程序,快速启动在计算以及网络方面都有相应的优化方案,在这篇文章中不再赘述。但是对于容器镜像的下载以及容器文件系统的构建,是我们今天讨论的重点。本文提出DPU (Data Processing Unit)/ IPU (Infrastructure processing Unit) 可以对容器的镜像以及文件系统的构建进行相应的卸载(offloading) 。//由于DPU 和IPU 是类似概念,文中后续内容主要采用IPU 这个说法。
2、解决方案
正常的容器启动,首先需要下载容器(container)的镜像(image),然后把下载来的容器的镜像层进行解压(unpack)操作,接着选择容器的一个Runtime time进行启动。当然目前也有一些工作,是在容器生命管理周期软件(诸如containerd)中采用特定snapshot实现,从而在容器启动后可以按需获取解压后的镜像内容。我们在2023年SDC会议上的议题 [1] 提出可以使用IPU进行容器启动前镜像的准备工作,包括镜像的管理以及unpack操作。那么容器的镜像将完全放入IPU,而不用存放在主机中。具体的做法:
容器的管理软件需要和IPU进行通信,即让IPU 完成整个容器镜像的准备工作;
接着IPU 通知主机中的管理软件(诸如containerd)镜像准备已经完成;
容器的管理软件进行正常的容器启动。
使用这样的方法后:1把容器镜像的管理,包括下载以及caching 完全放入IPU中;2把每个容器的镜像解压(unpack)操作也放入IPU。镜像可以直接解压到IPU中"块设备服务"的服务软件 (i.e., 基于SPDK [3]的virtual storage block service) 所提供的bdev中,然后通过PF/VF的形式透传给主机或者主机中运行容器的轻量级虚拟机。接着主机中的容器管理软件可以挂载相应的块设备,然后得到容器的rootfs 层,进行容器的正常启动。因为IPU中的块设备服务软件,可以提供块设备的快照(snapshot)和克隆功能(Clone),那么大规模部署中, 容器的rootfs可以使用相对较小的代价进行构建,因为不同的容器可以进行共享解压后的bdev,从而进一步提高容器启动速度,并提升空间使用效率。
此外,IPU也提供了一些基于硬件的加速器(诸如Intel E2000 IPU的LCE),可以进行容器镜像解压缩的加速。在这篇文章中, 我们会详细介绍这个方案,并且用简单的例子进行佐证。总的来讲,本文提出的方案可以很好的把IPU和云原生有机的结合起来。
本文的解决方案 VS 已有的块存储卸载方案
图1 给出了已有的IPU/DPU 对于主机虚拟存储设备的模拟,IPU通过PCIe协议,通过VF/PF 给主机提供一些虚拟的块设备,诸如Virtio-blk,virtio-SCSI, NVMe。然后主机通过相应的驱动,就可以操纵这些虚拟块设备。在这样的虚拟设备上,也可以创建文件系统,然后运行相应的程序。这样的卸载在多数场景下,满足了用户的需求,但是也有一定的局限性--用户还是需要构建自己的文件系统,不能进行更好的资源共享,比如文件系统级别的共享,包括PageCache等。
图 1 利用IPU 给主机提供块设备[4]
尤其是针对容器相关的应用(诸如FaaS), 这样的卸载显得不太彻底。比如对于容器来讲,一般会使用overlayFS的方式,进行解压后的镜像层管理。如果IPU 仅仅卸载块设备,而没有额外的功能,那么这样的事情都需要主机去完成,那么就会消耗主机大量的CPU 资源。
为此,我们提出IPU可以进行一些软件层面的增强,更好的服务这样的场景,如图2所示。
图 2 IPU 进行扩展支持容器镜像以及文件系统构建的卸载
此外,在图3中也给出了IPU 怎么和容器管理软件通信,进行有效的卸载。图3中存储的卸载服务软件,主要基于SPDK [3] 实现。FaaS/Container使用场景的卸载大致有以下步骤:
Orchestrator(如K8S/containerd/runC|Kata Containers)收到容器运行请求后与IPU通信。然后IPU接收到主机中来自上层运行软件(image-mgnt client)的请求。
Image-mgnt 服务从镜像注册中心下载动态镜像和基础镜像。
Image-mgnt 服务将镜像解压到到指定的 Bdev(例如图中的 Bdev2)。
然后,基于SPDK的存储服务指定传输层(例如,NPI for NVMe)将相应的包含容器文件系统的块设备(例如途中的Bdev2)通过 VF 或 PF 导出到主机。IPU通过RPC通知容器软件。
当 VM 或主机内核看到 VF/PF 时,加载相关设备驱动程序后最终获得块设备。然后容器管理软件将块设备(例如 /dev/sdX)通过IPU 给知的信息,通过相应的文件系统格式挂载到特定的挂载点。
通过这样的方式,上层容器管理软件就可以直接看到容器需要的文件系统,然后进行后续的容器的启动。在这个过程中,主机中不需要对容器的镜像下载以及文件系统的构建,花费额外的CPU 资源,为此可以节省出更多的CPU 资源,进行其他更重要的服务。
图 3 IPU 对容器文件系统构建的具体卸载流程图
3、讨论
这是一个可行的方案,在IPU中利用基于SPDK的存储服务,利用基于blobstore bdev 的clone/snapshot的功能,也可以实现一些简单的容器overlayfs的sharing。举个例子,比如主机需要启动50个类似的容器。这些容器都有两层镜像:一层是ubuntu22.04 基础镜像 (命名为ubuntu层),一层是每个容器自己的镜像层。那么对于ubuntu层相关的文件系统,可以在SPDK 中选取一个blobstore bdev ,加压镜像灌入相应的文件系统,然后对生成的基础bdev 进行clone操作,就可以生成很多不同的bdev,那么每个容器就可以基于各自clone后的bdev,进行后续文件系统的构建,最后IPU再把已经准备好文件系统的bdev 暴露给主机。此外对于K8S的一些容器管理,都是以pod 单位的,那么在一个bdev 中,也可以准备同一个pod 中不同容器的文件系统,这些都是没有问题的。对于怎么用IPU 构建相应的可以给容器使用的bdev,可以参考我们在SDC2022的presentation [1]或者SPDK 虚拟论坛2022的presentation [6] 。
目前我们的实践工作,主要解决了容器镜像卸载以及文件系统构建的工作,但是并没有解决主机在运行过程中,对于PageCache的共享。我们知道目前Kata Containers中可以使用virtiofs 把主机中的文件系统,直接共享给Kata Containers 管理的虚拟机,然后供容器使用,这样可以在运行过程中共享PageCache。不过这应该是在同一个Host OS 的环境下进行共享。
最近,我们观察到IBM 正在使用Bluefield进行一些virtio-fs [5] 卸载的POC 工作,参见[2] 。虽然主机和IPU 依然通过PCIe进行数据交换,但是不在是virtio-blk或者NVMe之类的块协议,而是带有文件系统信息的virtio-fs的协议。然后在IPU 中,对这些卸载的文件操作,可以卸载到本地的文件系统或者远端的NFS 系统。这样的工作非常有价值,但是怎样在主机和IPU 中共享Page Cache 依然是具有挑战性的工作,这个和在同一个host OS 环境中有很大的区别。也就是主机和IPU 需要协商好一些内存空间,进行一些page cache的共享,才能进一步加快container的启动,或者在container使用过程中进行共享。笔者认为,也许未来CXL(Compute Express Link)等技术可以解决这样的问题。
4、总结和后续
这篇文章中主要介绍了怎样使用IPU 对容器的镜像下载,文件系统的构建进行卸载。目前传统的IPU在存储方面,主要是对主机上块设备的一个卸载。文中的解决方案,主要针对IPU 对块设备的卸载,做了一定程度的扩展,简而言之,就是让IPU参与容器文件系统的构建,在IPU中准备好容器所需要的文件系统,依然通过块设备的方式暴露给主机使用。主机通过和IPU的交互,可以正确的使用块设备中的文件系统,进行容器的快速启动。此外,IBM开展了文件系统直接采用DPU/IPU 进行卸载 (即virtio-fs的卸载) ,提出了DPFS [2], 也就是使用直接卸载文件系统而不是块设备存储。这样的工作,目前在性能和功能方面都有一定的局限性,不过随着CXL技术和IPU的配合,也许可以达成,使得主机对于文件系统的卸载真正达成。
Reference
[1] Accelerating FaaS/container Image Construction via IPU.
https://www.snia.org/sites/default/files/SDC/2022/SNIA-SDC22-Yang-Li-Zeng-Accelerating-FaaS-Container-Image-Construction-via-IPU_0.pdf
[2] IBM DPFS.
https://github.com/IBM/DPFS
[3] SPDK website.
http://spdk.io
[4] VirtualBlockStorage. https://ipdk.io/documentation/Recipes/VirtualBlockStorage/
[5] Virtio-fs.
https://vmsplice.net/~stefan/virtio-fs_%20A%20Shared%20File%20System%20for%20Virtual%20Machines%20%28FOSDEM%29.pdf
[6] 利用IPU 加速FaaS/container image 构建.
https://ci.spdk.io/download/2022-virtual-forum-prc/D2_7_Ziye_Accelerating_FaaS_container_Image_Construction_via_IPU.pdf
作者:杨子夜 黄薪宇 刘孝冬 曾军
转载须知
DPDK与SPDK开源社区
公众号文章转载声明
推荐阅读
TADK v22.03 Release
手把手教你让英特尔®E810飞起来
点点“赞”和“在看”,给我充点儿电吧~