Nova通过独立的软件管理模块实现XenServer、Hyper-V和VMWare ESX的调用与管理,同时对于其他的Hypervisor,如KVM、LXC、QEMU、UML和Xen则是通过Libvirt标准接口统一实现,其中KVM是Nova-Compute中Libvirt默认调用的底层虚拟化平台。为了更好地理解在Nova环境下Libvirt是如何管理底层的Hypervisor,先要基本了解Libvirt的体系架构与实现方法。这部分详细内容请见另外一篇博文libvirt学习总结。
Libvirt是一种实现虚拟化平台能力交互的工具集,它为所支持的Hypervisor提供了一种通用的API接口套件,上层管理平台(如Nova)通过Libvirt来实现对虚拟机的生命周期管理。Libvirt当前支持以下底层虚拟化平台:
KVM:Linux平台仿真器;
QEMU:面向各种架构的平台仿真器;
Xen:面向IA-32、IA-64和PowerPC970架构的虚拟机监控程序;
LXC:用于操作系统虚拟化的Linux(轻量级)容器;
OpenVZ:基于Linux内核的操作系统级虚拟化;
User Mode Linux:面向各种架构的Linux平台仿真器;
VirtualBox:x86虚拟化虚拟机监控程序;
ESX、GSX:VMW爱热企业级虚拟化平台;
VMWare Workstation、VMWare Player:VMWare用户级虚拟化平台;
Hyper-V:Microsoft虚拟化平台。
另外,Libvirt支持以Bridging、NAT、VEPA和VN-LINK方式构建虚拟网络,以及支持基于不同制式的IDE/SCSI/USB disks、FibreChannel、LVM、iSCSI、NFS和filesystems存储。因此,Libvirt在功能性、兼容性以及管理等方面的优势十分明显。
Libvirt对底层虚拟化平台的调用与管理有两种方式:本地管理与远程管理。其中,本地管理模式下、上层管理平台系统、Libvirt、虚拟化平台以及客户虚拟机均不属在同一物理主机节点之上;远程管理模式下,上层管理平台系统与底层虚拟化平台以及客户虚拟机分别不属在不同的物理主机节点上。当所有的组件部署在同一物理节点时,上层管理平台系统通过Libvirt工作,以控制本地域中的所有底层虚拟化软件,该种方式在安全性、可靠性以及可扩展性方面存在一定弊端。因此,相比而言基于Libvirt的远程控制模式可以较好地解决本地管理模式所遇到的问题。
在Libvirt环境下,一台虚拟机随着用户需求的改变可能会经历如下状态:
Undefined:一台虚拟机的初始化状态,Libvirt对处于该状态的Guest Domain不执行任何创建或定义的操作;
Defined:只有持久类型的Domain存在本状态,Guest Domain已经被创建;
Running:基于某种Hypervisor的Guest Domain虚拟机已经正常运行,可被客户控制并操作;
Paused:Hypervisor上对该Guest Domain虚拟机执行挂起操作,状态被临时存储直至恢复;
Saved:类似于Paused状态,不同的是Guest Domain虚拟机的相关状态与数据被永久存储,当接收到客户请求恢复的指令之后,处于Saved状态下的Guest Domain虚拟机被恢复。
以上简要描述了Libvirt相关的管理能力与技术特征,Nova基于Libvirt在功能方面实现与底层虚拟化平台的无缝兼容。Nova对于底层Hypervisor(如KVM/QEMU等)的调用与管理主要通过LibvirtDriver类(见Nova源代码“nova/virt/libvirt/driver.py”)来实现,该类与类XenAPIDriver、VMwareESXDriver、HyperVDriver类似,均是ComputeDriver基类的一个特殊实现。LibvirtDriver类通过“_conn = property(_get_connection)”语句定义了一个连接属性,在执行虚拟机管理相关的操作时,调用LibvirtDriver实例的这个属性的同时,就意味着执行_get_connection方法,打开底层Hypervisor的连接。
Libvirt对Hypervisor的连接有两种方式:一种是只读式;另一种是认证式。只读式的连接只能对Hypervisor进行读访问,所允许的API调用集合有限,比较适合监控性的应用程序;认证式的连接能够经过认证对Hypervisor进行读写访问,但是需要包含一个认证参数才能执行相关的写操作。LibvirtConnection类中虽然能根据“ReadOnly”条件来选择其中一种方式,但是实际执行Nova时,由于“ReadOnly”参数的默认值是False,并且在建立Libvirt链接时并无修改,因此系统连接方式是认证是连接。Nova通过Libvirt建立于底层Hypervisor认证式连接的关键语句是“libvirt.openAuth(uri, auth, 0)”。其中,Libvirt作为一个Python模块,通过它能够调用Libvirt库中与Hypervisor相关的管理API;“uri”参数主要是连接到Hypervisor的入口地址,如系统要求连接到本地的Xen Hypervisor,其本地URI是“xen:///”;“auth”参数是提供相应的认证信息,进一步实现Libvirt对Hypervisor的读写操作。
以下选取创建虚拟机的进程具体说明Nova如何基于Libvirt实现对底层虚拟化平台的调用与管理。在LibvirtConnection类中,通过“spawn”方法来实现虚拟机的创建,“spawn”调用方法_create_domain_and_network来启动一个新的Domain,在方法_create_domain_and_network中,实际与Hypervisor建立连接的语句是“domain = self._conn.defineXML(xml)”;在建立与Hypervisor连接的基础上执行defineXML方法,创建并定义一个Domain,但是此时的Domain还未启动,必须执行“domain.createWithFlags(launch_flags)”语句来启动之前定义好的虚拟机Domain。
下面来详细的解析方法spawn,来看看OpenStack Nova中是如何应用Libvirt库来启动虚拟机的。
我们来看方法spawn:
接下来调用一个比较重要的方法_create_image来实现虚拟机镜像的建立,需要注意的是这个方法中还没有启动所建立的虚拟机实例。
代码的详细解析请见xxx