Run a Kata Container utilizing virtio-fs Once installed, start a new container, utilizing qemu + virtiofs: $ docker run --runtime=kata-qemu-virtiofs -it busybox Verify the new container is running with the qemu hypervisor as well as using virtiofsd. To do this look for the hypervisor path and the virtiofs daemon process on the host: $ ps -aux | grep virtiofs root ... /home/foo/build-x86_64_virt/x86_64_virt-softmmu/qemu-system-x86_64_virt ... -machine virt,accel=kvm,kernel_irqchip,nvdimm ... root ... /home/foo/build-x86_64_virt/virtiofsd-x86_64 ... You can also try out virtio-fs using cloud-hypervisor VMM: $ docker run --runtime=kata-clh -it busybox
1. 当前安全容器存储领域的问题
在介绍virtio-fs之前,我们先来了解一下当前安全容器存储领域遇到的问题,因为只有在理解了所要解决的问题才能更好的理解解决问题的方案。
在当前安全容器领域,Kata Containers可以说是最被广泛应用的容器技术了。Kata Containers使用轻量级虚拟机和硬件虚拟化技术来提供更强隔离,以构建安全的容器运行时。但也正是因为使用了虚拟机,容器的根文件系统(容器rootfs)无法像runc那样直接使用主机上构建好的目录,而需要有一种方法把host上的目录共享给guest。
目前基本上只有两种流派的方法能够透传host目录/数据给guest,一种是基于文件的方案,一个是基于块设备的方案。而这两种流派又都有各自有自身的优缺点,这里分别以9pfs和devicemapper为例来说明。
- 基于文件的9pfs
- 优点:因为使用host上overlayfs,能充分利用host pagecache;部署简单,不需要额外的组件
- 缺点:基于网络的协议,性能差;POSIX语义兼容性方面不好(主要体现在mmap(2)的支持上,在特殊情况下有数据丢失的风险)
- 基于块设备的devicemapper
- 优点:良好的性能;很好的POSIX语义兼容性
- 缺点:无法充分利用host pagecache,部署运维复杂(需要维护lvm volume)
可以看到,这两种流派优缺点基本互补。那么有没有一种解决方案能够结合两者的优点,同时能够克服两者的缺点呢?virtio-fs正是这种新的方案,为我们带来了新的曙光。
2. virtio-fs介绍
2.1 基本信息
virtio-fs是红帽在2018年12月10号在kata社区提出的一种在guest之间共享文件系统的方案。 项目主页:https://virtio-fs.gitlab.io/ 代码仓库:https://gitlab.com/virtio-fs 邮件列表:https://www.redhat.com/mailman/listinfo/virtio-fs
其主要设计目标为:
- 在不同guest之间,以快速、一致、安全的方式共享同一个host目录树结构
- 拥有较好的性能和跟本地文件系统(如ext4)一样的语义
主要使用场景:
- 在kata-container场景中替换9p,作为容器rootfs
- 为虚拟机在host和guest之间共享数据 (shared file system for virtual machines)
- File-system-as-a-Service,更安全
2.2 原理与架构设计
virtio-fs方案使用FUSE协议在host和guest之间通信。在host端实现一个fuse server操作host上的文件,然后把guest kernel当作fuse client在guest内挂载fuse,server和client之间使用virtio来做传输层来承载FUSE协议,而不是传统结构上的/dev/fuse设备。为了支持在不同guest中同时mmap(MAP_SHARED)同一个文件,virtio-fs把文件mmap进qemu的进程地址空间并让不同guest使用DAX访问该内存空间,这样就绕过了guest pagecache达到不同guest都访问同一份数据的目的,同时也在多个guest之间共享了内存,节省了内存资源。
简要架构图:
从图中我们可以了解到,virtio-fs主要由以下几个组件组成:
- guest kernel:作为fuse client来挂载host上导出的目录
- qemu:新添加的vhost-user-fs-pci设备用于在guest kernel和virtiofsd之间建立起vhost-user连接
- virtiofsd(同样在qemu仓库中):host上运行的基于libfuse开发的fuse daemon,用于向guest提供fuse服务
下图是更详细的架构图
virtio-fs跟其他基于文件的方案(比如9pfs或者NFS)相比,其独特之处在于virtio-fs充分利用了虚拟机和hypervisor同时部署在一个host上的特点以避免昂贵的VMEXITS。具体来说就是,DAX数据访问和元数据的共享内存访问都是通过共享内存的方式避免不必要的VM/hypervisor之间通信(在元数据没有改变的情况下),而共享内存访问也比基于网络文件系统协议访问要更轻量级也有更好的本地文件系统语义和一致性。这也是基于FUSE设计virtio-fs而不是基于其他网络文件系统协议做改进的原因。
了解virtio-fs原理与设计架构之后,我们可以总结出virtio-fs的几条设计要点,看其是如何同时拥有9pfs和devicemapper方案的优点,同时克服它们的缺点的:
- FUSE协议而不是基于网络的协议:更快的性能,更好的POSIX语义兼容性
- 独立的virtiofsd进程:更安全,且不需要维护单独的块设备(相比9pfs多了一个组件,但维护成本比devicemapper还是要小很多)
- Host/guest之间共享内存(DAX):进一步提升性能,同时节省内存资源
2.3 使用方法
说了这么多virtio-fs的好处,那么现在就来看看如何使用它吧。按照官方QEMU howto文档里描述的步骤即可。这里需要注意的是编译guest kernel的时候要确保打开了以下内核选项。
CONFIG_VIRTIO
CONFIG_VIRTIO_FS
CONFIG_DAX
CONFIG_FS_DAX
CONFIG_DAX_DRIVER
CONFIG_ZONE_DEVICE
- 首先运行virtiofsd,其中cache_size=4G表示DAX window大小
virtiofsd –o source=/export/source –o vhost_user_socket=/tmp/vhost-fs.socket,cache=none,cache_size=4G
- 然后启动guest,注意 tag=myfs 选项,mount时需要tag一致
qemu-system-x86_64 –chardev socket,id=char0,path=/tmp/vhost-fs.socket –device vhost-user-fs-pci,chardev=char0,tag=myfs,cache-size=2G …
- 最后在guest中mount virtio-fs
mount –t virtiofs myfs /mnt/virtiofs
2.4 社区状态及主要贡献者
virtio-fs从出现开始到现在经历里以下几个里程碑:
- 2018-12-10:RFC patch发布
- 2019-04-12:v0.1版本发布
- 2019-05-03:v0.2版本发布
- 2019-08-19:v0.3版本发布
- 2019-08-26:virtio-fs进入v5.4-rc2内核主线(不包含DAX相关代码)
到目前为止(2019-11)只有virtio-fs使用virtio传输FUSE协议部分的代码进入了内核主线,DAX相关修改没没有进入,qemu的代码已经发到qemu社区review,预计进入qemu主线不会太远了。
virtio-fs的最主要贡献者当然还是发起者和维护者红帽,除红帽之外我们阿里巴巴是最大的贡献者了,下图是v0.3版本发布的时候,维护者在邮件里列出的感谢列表,可以看到阿里巴巴占了很大比重。
3. virtio-fs性能及优化
说了virtio-fs这么多好话,那它实际的性能到底如何,就让我们来实际看一看,俗话说,是骡子是马拉出来遛遛。
3.1 性能数据
首先看一下维护者在v3 patch中给出的性能数据,我选取了其中部分数据做出图表(v3 patch中有详细测试设置与说明)。从图中我们可以看出virtio-fs对9pfs呈现出碾压式的优势。
当然,这只是benchmark的数据,那么实际使用起来效果如何呢?我们选取了build kernel这个工作中会经常用到的workload来实际测试,从下图可以看出,virtio-fs相比9p还是有明显的优势。
3.2 找到问题
从virtio-fs作者发出的v3 patch中也可以看出,测试的场景是一个相对理想的环境,也就是DAX做映射的window大小正好能够容纳测试文件的大小,作者也提到,当window大小小于文件大小的时候,会出现性能变慢的问题,因为这个时候virtio-fs需要做频繁的DAX window管理操作。
为了调查host pagecache和DAX window操作对性能到底有多大的影响,我们设计了4中场景,分别做测试,拿到数据作为分析的基础。这四种场景是:
- case1: 没有命中host page cache,且需要构建dax window的映射;
- case2: 没有命中host page cache,但不需要构建dax window映射;
- case3: 命中host page cache ,但需要构建dax映射;
- case4: 命中host page cache,且不需要构建dax映射;
测试结果如下:
从测试结果来看,host pagecache和DAX window操作都对性能有巨大的影响,所以当某个workload需要频繁操作DAX window的时候,性能会有比较大的回退。我们在实际测试当中也遇到了这样的case,就是当DAX window大小小于文件大小时做随机读测试,比如DAX window为2G,文件大小为5G的情况下,virtio-fs随机读性能甚至还不如9pfs。
3.3 性能优化
既然找到了问题,那么就有优化的方向和空间了。我们主要的优化方向也是在DAX window操作方面。下面分别列出我们在virtio-fs性能方面的优化,有些patch已经进入maintainer tree,有些还在review中。
3.3.1 fuse: Get rid of inode lock in range reclaim path
- Reclaim DAX mapping不需要获取inode lock,而引入引用计数,减少inode lock上的竞争
- 当mapping的引用计数大于1时,reclaim线程略过这个映射
- 在rand-read情况下性能有x10+倍的提升 (cache-size=2G, filesize=5G)
- https://gitlab.com/virtio-fs/linux/commit/a2c5838fb76c4634634b932db6dcabfd267842bc
3.3.2 virtio-fs: do not removemapping if dmap will be used immediately
- inline/direct reclaim时不发送removemapping请求,减少vmexit次数
- 在rand-read情况下性能有近2倍的提升 (cache-size=4G, filesize=10G)
- 由于存在deadlock风险,还没有merge
- https://www.redhat.com/archives/virtio-fs/2019-August/msg00141.html
3.3.3 virtiofs: FUSE_REMOVEMAPPING remove multiple entries in one call
- 减少removemapping请求的数量,如 truncate –s 0 testfile
- https://www.redhat.com/archives/virtio-fs/2019-May/msg00058.html
3.3.4 virtiofsd: enable PARALLEL_DIROPS during INIT
4. 总结
virtio-fs有着良好的POSIX兼容性和性能,而且是为安全容器量身打造的容器存储解决方案,解决了该领域长期以来的痛点,可以预见virtio-fs一定会成为安全容器存储领域下一个热点。但其还处于早期开发阶段,仍然有大量工作需要做,比如加入多队列的支持、补足运维能力(热升级等)、增强稳定性等等。
目前除了红帽之外,已经有阿里巴巴、Intel、Fujitsu、华为和ARM等厂商都对virtio-fs有浓厚的兴趣并且已经开始参与社区开发和测试,其中我们阿里云操作系统组-袋鼠团队又是除红帽之外最大的贡献者。也欢迎感兴趣的同学们赶紧行动起来,来贡献bug report和patch吧!