libvirt是目前使用最为广泛的对KVM虚拟机进行管理的工具和应用程序接口(API),而且一些常用的虚拟机管理工具(如virsh、virt-install、virt-manager等)和云计算框架平台(如OpenStack、OpenNebula、Eucalyptus等)都在底层使用libvirt的应用程序接口。
libvirt本身提供了一套较为稳定的C语言应用程序接口,目前,在其他一些流行的编程语言中也提供了对libvirt的绑定,在Python、Perl、Java、Ruby、PHP、OCaml等高级编程语言中已经有libvirt的程序库可以直接使用。libvirt对多种不同的Hypervisor的支持是通过一种基于驱动程序的架构来实现的。libvirt对不同的Hypervisor提供了不同的驱动:对Xen有Xen的驱动,对QEMU/KVM有QEMU驱动,对VMware有VMware驱动。
libvirt作为中间适配层,让底层Hypervisor对上层用户空间的管理工具是可以做到完全透明的,因为libvirt屏蔽了底层各种Hypervisor的细节,为上层管理工具提供了一个统一的、较稳定的接口(API)。通过libvirt,一些用户空间管理工具可以管理各种不同的Hypervisor和上面运行的客户机,它们之间基本的交互框架如图1-1所示。
图1-1 虚拟机管理工具通过libvirt管理各种类型的虚拟机
在libvirt中涉及到几个重要的概念,解释如下:
1. 节点(Node):一个物理机器,上面可能运行着多个虚拟客户机。Hypervisor和Domain都运行在Node之上。
2. Hypervisor:也称虚拟机监控器(VMM),如KVM、Xen、VMware、Hyper-V等,是虚拟化中的一个底层软件层,它可以虚拟化一个节点让其运行多个虚拟客户机(不同客户机可能有不同的配置和操作系统)。
3. 域(Domain):是在Hypervisor上运行的一个客户机操作系统实例。域也被称为实例(instance,如亚马逊的AWS云计算服务中客户机就被称为实例)、客户机操作系统(guestOS)、虚拟机(virtual machine),它们都是指同一个概念。
关于节点、Hypervisor和域的关系,可以简单地用图1-2来表示。
在了解了节点、Hypervisor和域的概念之后,用一句话概括libvirt的目标,就是:为了安全高效的管理节点上的各个域,而提供一个公共的稳定的软件层。当然,这里的管理,既包括本地的管理,也包含远程的管理。具体地讲,libvirt的管理功能主要包含如下五个部分:
(1)域的管理:包括对节点上的域的各个生命周期的管理,如:启动、停止、暂停、保存、恢复和动态迁移。也包括对多种设备类型的热插拔操作,包括:磁盘、网卡、内存和CPU,当然不同的Hypervisor上对这些热插拔的支持程度有所不同。
(2)远程节点的管理:只要物理节点上运行了libvirtd这个守护进程,远程的管理程序就可以连接到该节点进程管理操作,经过认证和授权之后,所有的libvirt功能都可以被访问和使用。libvirt支持多种网络远程传输类型,如SSH、TCP套接字、Unix domain socket、支持TLS的加密传输等。假设使用最简单的SSH,则不需要额外配置工作,比如:example.com节点上运行了libvirtd,而且允许SSH访问,在远程的某台管理机器上就可以用如下的命令行来连接到example.com上,从而管理其上的域。virsh -c qemu+ssh://[email protected]/system
(3)存储的管理:任何运行了libvirtd守护进程的主机,都可以通过libvirt来管理不同类型的存储,如:创建不同格式的客户机镜像(qcow2、raw、qde、vmdk等)、挂载NFS共享存储系统、查看现有的LVM卷组、创建新的LVM卷组和逻辑卷、对磁盘设备分区、挂载iSCSI共享存储,等等。当然libvirt中,对存储的管理也是支持远程管理的。
(4)网络的管理:任何运行了libvirtd守护进程的主机,都可以通过libvirt来管理物理的和逻辑的网络接口。包括:列出现有的网络接口卡,配置网络接口,创建虚拟网络接口,网络接口的桥接,VLAN管理,NAT网络设置,为客户机分配虚拟网络接口,等等。
(5)提供一个稳定、可靠、高效的应用程序接口(API)以便可以完成前面的4个管理功能。
libvirt主要由三个部分组成,它们分别是:应用程序编程接口(API)库、一个守护进程(libvirtd)和一个默认命令行管理工具(virsh)。应用程序接口(API)是为了其他虚拟机管理工具(如virsh、virt-manager等)提供虚拟机管理的程序库支持。libvirtd守护进程负责执行对节点上的域的管理工作,在用各种工具对虚拟机进行管理之时,这个守护进程一定要处于运行状态中,而且这个守护进程可以分为两种:一种是root权限的libvirtd,其权限较大,可以做所有支持的管理工作;一种是普通用户权限的libvirtd,只能做比较受限的管理工作。virsh是libvirt项目中默认的对虚拟机管理的一个命令行工具。
- 卸载原有版本libvirt
# yum remove libvirt- 安装依赖包
# yum -y install gcc yajl-devel libxml2-devel device-mapper-devel libpciaccess-devel libnl-devel- 重新下载源码、编译安装
# wget http://libvirt.org/sources/libvirt-1.2.21.tar.gz
# tar -zxf libvirt-1.2.21.tar.gz
# cd libvirt-1.2.21
# ./configure
# make –j 4
# make install- configure: error: You must install the libyajl library & headers to compile libvirt
# yum -y install yajl-devel- libxml2 xml2-config >= 2.6.0 … configure: error: Could not find libxml2 anywhere (see config.log for details).
# yum install libxml2-devel- configure: error: You must install device-mapper-devel/libdevmapper >= 1.0.0 to compile libvirt
# yum -y install device-mapper-devel- Transaction check error:
file /etc/rc.d/rc.local from install of systemd-219-30.el7_3.9.x86_64 conflicts with file from package engine-0.5.0-1.x86_64
file /etc/systemd/journald.conf from install of systemd-219-30.el7_3.9.x86_64 conflicts with file from package engine-0.5.0-1.x86_64
# yum -y remove engine-0.5.0-1.x86_64- configure: error: You must install the pciaccess module to build with udev
# yum -y install libpciaccess-devel- configure: error: libnl-devel >= 1.1 is required for macvtap support
# yum -y install libnl-devel
目前对KVM使用最为广泛的管理工具(应用程序接口)就是libvirt。Libvirt本身构建于一种抽象的概念上,它为受支持的虚拟机监控程序实现常用功能提供通用的API。Libvirt提供了操作KVM的原生层接口,可以实现对虚拟机的基本管理操作。Libvirt库用C实现,且包含对python的直接支持。Libvirt-python就是基于libvirt API的python语言绑定工具包,通过该包可以实现对VM日常管理和监控数据的获取。利用python通过调用libvirt API获取VM的监控信息。
1、通过导入libvirt模块,然后连接本地qemu虚拟机监控程序。获取宿主机上每个instance的domain并获取一些基本信息。
新建一个python执行文件,命名为test.py,内容如下:
import libvirt
conn=libvirt.open("qemu:///system")
for id in conn.listDomainsID():
domain=conn.lookupByID(id)
print domain.name()
print domain.UUIDString()
print domain.info()
conn.close()
编译:
[root@localhost python]# python test.py
ubuntu
37e809da-ccb8-45f4-b7ac-5d23803fedc4
[1, 10485760L, 10485760L, 8, 350694330000000L]
返回列表参数说明:
[State:1, Max memory:2097152L, Used memory:2097152L, CPU(s):2, CPU time:4245630000000L]
2、 获取cpu的使用率
Libvirt中不能直接获取虚拟机的cpu使用率但是可以通过cputime来计算出实际的使用率,计算公式为:
首先得到一个周期差:cputime_diff = (cpuTimenow — cpuTimet seconds ago)
然后计算实际使用率:%cpu = 100 × cpu_time_diff / (t × nr_cores × 109),实现:
import libvirt
import time
conn=libvirt.open("qemu:///system")
for id in conn.listDomainsID():
domain=conn.lookupByID(id)
t1=time.time()
c1=int(domain.info()[4])
time.sleep(1);
t2=time.time();
c2=int(domain.info()[4])
c_nums=int(domain.info()[3])
usage=(c2-c1)*100/((t2-t1)*c_nums*1e9)
print "%sCpuusage%f" %(domain.name(),usage)
conn.close()
3、获取网络流量
可以利用dom.interfaceStats(interface)获取虚拟网卡的流量信息,但是该方法需要传递一个虚拟网卡名做为参数。可以使用libvirt的API获取domain的情况,并获取xml配置文件。通过xml的tree来获取每个可用的要监测设备的名称,再通过domain去获取设备的属性字段值即是要监控的数值。
import libvirt
from xml.etree import ElementTree
conn=libvirt.open("qemu:///system")
for id in conn.listDomainsID():
domain=conn.lookupByID(id)
tree=ElementTree.fromstring(domain.XMLDesc())
ifaces=tree.findall('devices/interface/target')
for i in ifaces:
iface=i.get('dev')
ifaceinfo=domain.interfaceStats(iface)
print domain.name(),iface,ifaceinfo
conn.close()
[root@localhost python]# python interface_network.py
lisq_ubuntu vnet1 (12990092547L, 148560008L, 0L, 24474L, 5829122366L, 15642345L, 0L, 0L)
gw_vm1 vnet0 (8626034144L, 77478909L, 0L, 1772L, 7449690322L, 20937751L, 0L, 0L)
gw_vm1 vnet4 (7495353029L, 110636521L, 0L, 0L, 102051106L, 1594664L, 0L, 0L)
onos_env vnet2 (33638615113L, 237797482L, 0L, 1587L, 26590860611L, 120627019L, 0L, 0L)
ubuntu vnet3 (10417110437L, 117327820L, 0L, 2936L, 1301705L, 20302L, 0L, 0L)
返回结果说明:
(rx_bytes:24194376L, rx_packets:363592L, rx_errs:0L, rx_drop:0L, tx_bytes:852996L, tx_packets:20302L, tx_errs:0L, tx_drop:0L)
4、获取磁盘信息
获得磁盘的总量和已使用量,可以通过dom.blockInfo(dev)获取。该方法需要传递一个参数,可以使用libvirt的API获取domain的情况,并获取xml配置文件。通过xml的tree来获取每个可用的要监测设备的名称,再通过domain去获取设备的属性字段值即是要监控的数值。
import libvirt
from xml.etree import ElementTree
conn=libvirt.open("qemu:///system")
for id in conn.listDomainsID():
domain=conn.lookupByID(id)
tree=ElementTree.fromstring(domain.XMLDesc())
devices=tree.findall('devices/disk/target')
for d in devices:
device=d.get('dev')
try:
devinfo=domain.blockInfo(device)
except libvirt.libvirtError:
pass
print domain.name(),device,devinfo
conn.close()
[root@kvmopt]#pythonlibvirt_test.py
instance1vda[42949672960L,2233990656L,2300968960L]domain.blockInfo(device)
返回结果说明:
(capacity:42949672960L, allocation:2233990656L,physical:2300968960L)
5、获得内存信息
可以通过domain.memoryStats()来获取memory的相关信息。
import libvirt
conn=libvirt.open("qemu:///system")
for id in conn.listDomainsID():
domain=conn.lookupByID(id)
domain.setMemoryStatsPeriod(10)
meminfo=domain.memoryStats()
print meminfo
conn.close()
[root@localhost python]# python memory.py
{'swap_out': 0L, 'available': 10239888L, 'actual': 10485760L, 'major_fault': 7196L, 'swap_in': 0L, 'unused': 7108400L, 'minor_fault': 28391051L, 'rss': 4677484L}
其中actual是启动虚机时设置的最大内存,rss是qemu process在宿主机上所占用的内存,unused代表虚机内部未使用的内存量,available代表虚机内部识别出的总内存量,那么虚机内部的内存使用量则是可以通过(available-unused)得到。
其实可以使用libvirt的命令行工具获取并查看虚机的内存信息
具体操作如下:
[root@localhost python]# virsh dommemstat 3
actual 10485760
swap_in 0
rss 2771500
如果出现如上情况,是因为在VM内没有安装virtio驱动,所有不能获取VM内存的详细信息。
正常在VM内部安装virtio驱动并且支持memballoon,执行上述操作可以看到如下结果:
$virsh dommemstat instance1
actual2097152
swap_in0
swap_out0
unused1367032
available2050112
rss743604
注意:
要获取VM内存使用详细信息,VM中需要安装virtio驱动并且支持memballoon。关于virtio驱动:Linux一般都会包含(通过 lsmod | grep virtio 查看),但是windows的virtio驱动需要自己在镜像中安装。