基于Nomad的Libvirt虚拟机运行时设计与实现(2)

934 阅读8分钟

3.3 Libvirt虚拟机运行时架构设计

上文分析了Nomad运行时驱动插件机制,采用运行时驱动接口的方式,本节设计和实现基于Nomad的边缘计算平台的Libvirt虚拟机运行时,这里取名为nomad-driver-libvirt。

选择使用Libvirt技术来实现虚拟机运行时,一是本文的边缘计算平台希望逐渐支持多种虚拟化平台,便于遗留系统迁移,然而,如图3.3所示,参考ETSI发布的NFV参考框架,虚拟基础设施管理(Virtualized Infrastructure Manager,VIM)层中提供的Hypervisor,又称虚拟机监视器(Virtual Machine Monitor,VMM)技术多种多样,每种技术提供的驱动和API又不尽相同,需要对不同的虚拟化技术调用不同管理工具,做到控制管理已经比较麻烦;二是虚拟化技术发展很迅速,可能新的虚拟化技术更符合应用的场景,平台未来有潜在的向不同Hypervisor下迁移的功能扩展的需求,管理平台需要大幅改动,这也更加困难。本文使用分层的设计,采用Libvirt通过在VIM层和虚拟网络功能管理(Virtual Network Functions Manager,VNFM)层之间构建一个抽象层,提供统一API供上层调用,下层统一封装不同虚拟机,从而方便实现对虚拟机的管理。网络功能虚拟化基础设施(Network Functions Virtualization Infrastructure,NFVI)和VIM层一同构成了IaaS层。NFVI是用来托管和连接虚拟功能的一组资源,包含了服务器、Hypervisor、操作系统、虚机、虚拟交换机和网络资源等,而Nomad是边缘计算平台的核心组件网络功能虚拟化编排器(Network Functions Virtualization Orchestrator,NFVO),执行资源编排和网络服务编排以及其他功能。

image.png

图3.3  NFV ETSI参考框架

Nomad的VIM实例化模型设计如图3.4所示。

image.png

图3.4  基于Nomad的VIM实例化模型

通过Nomad Client在0.9版本之后推出的插件机制,实现nomad-libvirt-driver的Libvirt虚拟机运行时,将编译的二进制文件放在Nomad插件加载目录下。Nomad Client启动时,启动nomad-libvirt-driver进程,这是需要实现的用户空间管理工具,如图3.5所示,原理是使用Libvirt Golang语言绑定的API,与libvirtd守护进程通信,进行虚拟机的管理。

image.png

图3.5  Libvirt虚拟机运行时支持的原理概要图

nomad-driver-libvirt是为了边缘计算平台管理虚拟机的需求而设计和实现的,初衷是方便虚拟机任务的管理,能够迁移一些遗留系统。不用像已有的云计算平台如oVirt、OpenStack等的管理功能那么丰富强大,那样就本末倒置了,就是实现需求最主要的那部分,目前就是单个节点上的多个VM管理,需要实现启动、执行、停止、查看、等待、销毁、恢复虚拟机作业,监控数据采集等功能,理论上可以支持Xen、KVM、VMWare、VirtualBox、Hyper-V等虚拟机监视器,目前主要针对KVM开发实现和验证。KVM是一个内核模块,它可以模拟虚拟机的CPU,但虚拟机的I/O设备是通过QEMU这个用户空间程序来模拟的,QEMU本身就有一套完整的开源的全虚拟化解决方案。

然而,Nomad运行时驱动接口在设计之初的抽象,更多地是基于不同的容器工作负载,当然也兼顾了部分非容器工作负载,但在部分功能的设计上仍有偏向性。以在虚拟机内执行命令为例,虚拟机的类型不同,命令都是相对于具体的操作系统的,用户对于虚拟机,更倾向和习惯IaaS方式地登陆虚拟机进行操作,这是虚拟机工作负载不具备容器特色的能力造成的。以资源限制为例,轻量级的容器技术采用Cgroups和Namespace技术,而基于传统操作系统虚拟化的技术,虚拟机实例的资源隔离和限制的边界并不是Cgroups,虚拟机在创建时可以指定所需资源的大小。Nomad驱动插件机制中的taskHandle回调可用于Libvirt虚拟机运行时驱动从崩溃中恢复,其中字段taskHandleVersion用于任务配置模式的修改和迁移。

初步设计和实现的边缘计算平台Libvirt虚拟机运行时,主要先支持QEMU/KVM虚拟机,涉及计算、存储、网络虚拟化等部分,考虑到CPU、磁盘、网络的硬件型号和运行模式等有繁杂的类型和配置,当前Libvirt虚拟机运行时优先支持常见的CPU类型,存储支持裸磁盘、分区和逻辑卷等,网络重点支持NAT、DHCP网络和桥接网络,虚拟机镜像支持QCOW2格式。以此实现的框架,后期扩展也较为方便。

以下对Libvirt虚拟机运行时分计算、存储、网络三方面考量。

计算方面,CPU的虚拟化技术可以使单CPU模拟多CPU并行,允许一个平台同时运行多个操作系统。Libvirt主要支持三种CPU模式:

(1)host-passthrough:Libvirt令KVM把宿主机的CPU指令集全部透传给虚拟机。因此虚拟机能够最大限度的使用宿主机CPU指令集,故性能是最好的。但是在热迁移时,它要求目的节点的CPU和源节点的一致。

(2)host-model:Libvirt根据当前宿主机CPU指令集从配置文件 /usr/share/libvirt/cpu_map.xml几十种类型中选择一种最相配的CPU型号。在这种 模式下,虚拟机的指令集往往比宿主机少,性能相对host-passthrough模式要差一点,但是热迁移时,它允许目的节点CPU和源节点的存在一定的差异。

(3)custom:这种模式下虚拟机CPU指令集数最少,故性能相对最差,但是它在热迁移时跨不同型号CPU的能力最强。此外,custom模式下支持用户添加额外的指令集。

三种模式的性能:host-passthrough优于host-model,host-model优于custom;三种模式的热迁移通用性custom优于host-model,host-model优于host-passthrough。

Libvirt虚拟机运行时实现默认配置为host-model模式,也支持host-passthrough设备透传提升性能。实际环境中多采用Intel E5系列的CPU,但是该系列的CPU也有多种型号,常见的有Xeon,Haswell,IvyBridge,SandyBridge等等。即使是host-model,在这些不同型号的CPU之间热迁移虚拟机也可能失败。所以从热迁移的角度,在选择host-mode时:需要充分考虑既有宿主机类型,以后采购扩容时,也需要考虑相同问题,除非不存在热迁移的场景,否则不应选择host-passthrough。

存储方面,物理内存的虚拟化使得应用程序认为其自身拥有连续的地址空间。而实际,应用程序的代码和数据在内存中可被分隔多个不连续页或段,甚至被交换到磁盘、闪存等外部存储器上,即使物理内存不足,应用程序也能顺序执行。Libvirt也有繁杂的存储设备类型的支持。

Libvirt虚拟机运行时当前以QCOW2格式存储虚拟机镜像,相比容器镜像,编译后的虚拟机镜像,几乎不支持元数据注入。虚拟机镜像的存储,也可以建设相应的虚拟机镜像仓库。

网络方面,Libvirt的网络类型和模式也比较复杂。Libvirt用户模式网络(默认的网络模式)完全由QEMU实现,不依赖其他工具,是QEMU使用slirp实现的一整套TCP/IP协议栈,并使用这个协议栈实现了一整套虚拟的NAT网络。这种方式优点在于简单、独立性好、不需要root权限,性能较差、不支持部分网络功能如ICMP协议、不能从宿主机和外部网络访问客户机。此外,Libvirt的MACvTap共有四种方式:VEPA、bridge、private、passthrough。从需求出发,本文Libvirt虚拟机运行时当前只计划支持NAT和Bridge两种网络方式。

NAT方式适用于桌面主机的虚拟化。NAT网络拓扑结构如图3.6所示。NAT方式的网络支持宿主机与虚拟机的相互访问,同时也支持虚拟机访问互联网,但不支持外界访问虚拟机。

image.png

图3.6  Libvirt NAT网络拓扑结构图

Bridge方式适用于服务器主机的虚拟化。Bridge网络拓扑结构如图3.7所示。Bridge方式即虚拟网桥(Virtual Bridge)的连接方式,该方式比NAT网络复杂一些,可以使虚拟机成为网络中具有独立IP的主机,能够和子网里面的机器互相通信。

image.png

图3.7  Libvirt Bridge网络拓扑结构图

桥接网络,客户机和宿主机共享一个物理网络设备连接网络。网桥多用作高级设置,特别是主机有多个网络接口的情况。

NAT网络和Bridge网络在宿主机上可以同时创建,但客户机只能选择其中一种。

日志方面,Libvirt提供了日志记录的,但有很多局限性。虚拟机内部的系统是完整的,其中运行的应用日志记录是在虚拟机内部的,随虚拟机镜像的销毁而销毁;另一方面,其中的应用日志不易于迁移,需要额外借助第三方日志工具,这些也算在虚拟机运行的负载中,是额外的开销。Libvirt虚拟机运行时从统一性的角度沿用了Nomad的日志工具类和日志风格。