导读 | 大家好,本次肖力分享的主题是KVM&Libvirt基本概念及开发杂谈,内容有些凌乱松散,主要基于自己早期整理的笔记内容和实践感悟,有些内容难免有失偏颇,望见谅。前面先介绍下需要了解的基本知识,大部分内容在肖力著作中都有更详细的解释,可阅读参考。 |
KVM包含:
1.内核模块kvm.ko,用于核心虚拟框架。 2.包含与处理器相关的模块kvm-intel.ko,kvm-amd.ko 3.kvm需要使用经过修改定制的qemu软件提供用户空间工具 *内核组件已经包含在Linux内核2.6.20中了 *部分操作系统在kvm中运行仍然存在某些问题,可以查看KVM官网提供的操作系统运行兼容性状态列表
使用KVM的前提条件:
1.qemu-kvm-release.tar.gz 2.kvm-kmod-release.tar.bz2,自己编译内核模块的需要这个东东 3.支持VT技术的Intel处理器或支持SVM技术的AMD处理器
使用qemu前提条件:
1.zlib库及头文件 2.sdl库及头文件 3.alsa库及头文件,这个是用来提供虚拟化音频相关功能,默认是禁用的,现在不知道什么状态了,可以使用--enable-alsa来启用 4.gnutls库及头文件,可选的VNC TLS支持,默认此功能是开启的,可以用--disable-vnc-tls关闭 5.kernel头文件 *创建,安装,运行KVM虚机,需要使用QEMU提供的用户空间工具,以前是分开发布的,现在分支已经合并,成为qemu-kvm。 *libvirt为用户提供了同不同虚拟化技术交互的抽象接口。
libvirt基本理念:
1.同linux虚拟化技术进行交互 2.免费,自由 3.稳定的C语言API 4.其他通用语言的绑定开发接口(java,python,perl,php。。。) 5.针对DMTF虚拟风格 6.QMF代理,用于AMQP、QPID信息系统
libivrt支持度:
虚拟技术:kvm/qemu, XEN, LXC, OpenVZ, UserModeLinux, VB, ESX, HyperV, PowerVM, Parallels, Bhyre
虚拟网络:桥接,NAT,VEPA,VNLINK
存储:IDE、SCSI,USB,FC,LVM,ISCSI,NFS,FS
libvirt对各种开发语言的支持:
1.直接支持c和c++,其他通过绑定支持 2.C#,JAVA,OCAML,Perl,PHP,Python 3.libvirt直接支持python,如果是通过安装包安装而不是源码编译的,需要确保安装合适的包,在RHEL中,叫libvirt-python,在ubuntu中叫python-libvirt,其他平台可能有不同的名字。
URI:用于连接或远程连接到宿主机的libvirt虚拟环境,类似数据库的连接字符串
1.指定URI连接到libvirt:通过把name参数传递到virConnectOpen或virConnectOpenReadOnly方法: virConnectPtr conn = virConnectOpenReadOnly("xxx:///default"); 2.为节省管理员时间,可以在libvirt客户端配置文件中配置URI别名, 配置文件位置/etc/libvirt/libvirt.conf(针对root用户)或$XDG_CONFIG_HOME/libvirt/libvirt.conf(针对非特权用户),可用下面语法设置别名 uri_aliases = [ "miaomiao=xxx://xxx@www.xxx.com.cn/system", "wangwang=xxx://xxx@www.xxx.com/system" ] 别名由a-z,0-9,_等字符组成,URI别名会应用到任何打开libvirt连接的应用中,除非把参数VIR_CONNECT_NO_ALIASES传给virConnectOpenAuth, 如果别名中包含非法字符,则不做任何别名查找。 如果URI传递给virConnectOpen参数为NULL,则libvirt会用下面规则确定URI: 1.环境变量:LIBVIRT_DEFAULT_URI 2.客户端配置文件:uri_default参数 3.探测每个虚机管理器知道找到一个可用的
libvirt基本概念:
node:节点,宿主机,一个node是一个单独的物理机,用于运行虚机
hypervisor:一个软件层,可以把一个物理机用不同的配置虚拟化为多个虚机的集合
domain:虚拟机,在容器级虚拟化情况中,是一个子系统,运行在由hypervisor提供的机器上
libvirt:提供一个通用的软件层,安全高效的管理node上的domain,同时实现远程管理功能。
*在windows系统中使用libvirt java绑定,需要使用libvirt java库,jna.jar库及对应平台的dll文件,如果报错:找不到dll或找不到相关模块时,需要安装virtviewer 在java代码中加入: System.setProperty("jna.library.path", "c:\\program files\\VirtViewer\\bin"); 并需要在上面路径放置一份virt-0.dll文件副本,命名为virt.dll
SPICE:
SPICE服务端是一个用libspice实现的VDI库,VDI定义了一系列接口来发布虚拟设备。(如:显示设备,键盘,鼠标)并且能让不同的spice组件和这些设备交互,从一方面来说,服务端使用spice协议同客户端通信,从另一方面来说,服务端同VDI主机应用进行交互如QEMU。 SPICE客户端是最终用户所面对的接口。
QXL设备和驱动
当libspice与qemu结合使用时,QEMU QXL PCI设备可以用来提升远端显示性能,增强客户机的图形系统。QXL设备需要客户机QXL驱动支持。 SPICE协议支持一种通信信道,此通道连接客户和服务端的代理,当使用QEMU时,SPICE代理位于客户机,VDI端口是一个QEMUPCI设备,可以与此代理进行通信。
SPICE有六大通道:
主通道:控制与配置
显示通道:图形命令,图形,视频流
输入通道:键盘和鼠标输入
光标通道:定位设备的位置与光标形状
回放通道:服务端的声音在客户端播放
录制通道:从客户端进行音频捕获
SPICE图像压缩功能:
SPICE本身提供了多种图像压缩算法,可以在服务器初始化时进行选择,也可以在运行期动态选择. QUIC是SPICE专有的图像压缩算法,此技术基于SFALIC算法,Lempel_zip(LZ)算法同样也是SPICE支持的算法。QUIC和LZ都是本地算法,独立编码每一个图像。全局LZ(GLZ)是另一个SPICE专有算法,与LZ同基于历史的全局字典表共同使用,GLZ可以在大量图像之间使用重复表达式来降低流量消耗,从而保存带宽。特别适合在低带宽的广域网环境中使用。 SPICE同样提供了一个针对每一个图像自动选择压缩算法的工作模式,通过图像属性启发式的选择LZ,GLZ,QUIC算法。 从理论上讲,LZ、GLZ更适合压缩合成图像,QUIC更适合压缩真实图像.
视频压缩:
SPICE使用低损压缩算法压缩发送到客户端的图像,但是视频流却是使用不同的方法来处理。SPICE服务端使用自启发方式标记动态视频区域并把他们作为视频流发送出去,编码使用mjpeg,这种处理方法在某种程度上节约了流量,提高了spice性能,尤其在广域网环境中。可是在某些情况下,这种启发行为可能会导致低质量的图像效果,比如把不断更新的文本区域识别为视频区域,从而导致部分区域图像效果质量低下。
从源代码编译,需要以下组件:
*qpixman:一个控制像素区域的通用库,包括低级别像素控制程序,同时也被cairo库使用,cairo是一个用于支持多输出设备的2D图形库,qpixman是pixman的轻量级修改版
*qcairo:cairo是一个矢量图形设备无关库,qcairo是cairo的轻量级修改版 *celt:CELT是一种音频压缩算法,以高质量传输音乐,信号会有非常小的延迟 *ffmpeg:是一个用于音频和视频重编码,转换,流传输的库。包括libarcodec音频视频编码库 *log4cpp是一个灵活的日志记录库,可以针对文件,syslog等,继log4j之后成型
*关于windows虚机安装virtio硬盘驱动的问题,一种方式是在安装系统的过程中加在virtio驱动光盘或软盘(winxp),如果系统已经装完,可以先创建一个小磁盘镜像, qemu-img create -f qcow2 xxx.img 1G 编辑虚机配置文件,加入此硬盘镜像,设置参数dev='vdc' bus='virtio'启动系统后会发现新硬件,选ISO镜像中对应的virtiosto驱动选virtioscsi驱动关闭vm,修改虚机配置,删除小硬盘镜像,把原磁盘改为dev='vda' bus='virtio'并删除地址部分,启动系统查看驱动情况。
*关于已有libvirt时自己编译libvirt时导致libvirt-sock不存在情况,该位置在/run/user/1000/libvirt/libvirt-sock或/usr/local/var/run/libvirt/libvirt-sock,编译后加在libvirtd守护进程,用netstat查看libvirt-sock是否在配置文件制定位置侦听。
使用java的libvirt开发API时注意:
* 在使用java程序编写libvirt应用时,当虚机处于pmsuspended状态时是无法获取domainInfo信息,会出现数组越界的错误提示。
* 使用attachDevice方法添加设备时要注意,flag=0时,表示执行结果影响当前状态,当前状态为运行状态,则只有运行时存在,当前状态为关闭状态则影响关机配置文件。flag=1时,表示影响运行时状态,执行此方法时,虚机必须处于Active状态。flag=2时,表示影响虚机持久配置文件,但是在qemu环境中flag=1会不支持,程序会爆出不支持热插拔,可以使用domainUpdateDeviceFlags进行换盘操作。 更新持久配置文件后,需要关机重新启动以使新配置生效。domain.getXMLDesc()方法获取的是虚机的运行时配置,而不是持久化配置,所以会看到被删除的设备仍然还在。
* 使用DomainUpdateDeviceFlags()方法更新虚机配置时,使用updateFlags 0或1都会更新处于Active状态的虚机运行时配置,在虚机重启后会保持这种更新,因为重启虚机不会重新加载持久化配置,关机之后重新开机,配置会还原为原先配置。 当使用updateFlags为2时,会出现无法更新的情况,虽然方法会执行成功,但无法更新持久配置文件。在关机状态下,使用updateFlags=1时,会报错,因为更新Live状态只能在domain的active状态下执行。
* 需要注意的是Libvirt不支持cdrom、floppydisk驱动器的热插拔,使用attachDevice()方法时,制定flags为0或1时,某些设备类型如CDROM对运行时修改可能会返回失败,原因是hypervisor底层驱动不支持。如果对正在进行块复制的设备进行detach()方法操作,hypervisor可能会阻止detach()的操作,在这种情况下,需要先使用domainBlockJobAbort()方法先停止该复制操作即可。
* 根据hypervisor和设备类型的不同,在一个处于active状态的domain中去除一个设备的操作可能是异步执行的,也就是说,当你执行detach()方法时,仅仅是请求去除一个设备,实际去掉此设备的时间可能是之后的一段时间,这是根据虚拟层与客户os配合完成的。这往往容易被忽略,因为有时会看到在配置文件中此设备已经被删除了,但hypervisor可能还没有真正删除这个设备,这可能会导致某些后续操作的失败。想要检查设备是否真的被成功删除了,要么重新使用domainGetXMLDesc()方法,要么为DOMAIN_EVENT_ID_DEVICE_REMOVED增加一个事件处理器,如果当detachDeviceFlags()方法返回时,设备已经被删除,事件会在API CALL结束之前触发。为了帮助现有的客户端在大多数情况下更好的工作,这个API会尝试把在请求之后过了一段时间才完成的异步删除操作转变为同步删除操作,换句话说,API在异步操作的情况下会等待一会儿来让删除操作得以完成。 注意,热插拔设备不会保持,一旦domain进入S4状态即hibernation状态,除非同样修改了domain的持久配置文件。
* 使用setMaxMemory()方法设置虚机最大内存时,默认使用的是AFFECT_CURRENT,也就是说当domain关闭时,修改持久化配置文件,当domain处于active状态时,修改运行时配置或运行时持久化配置都修改,这个要看hypervisor的行为而定。例如,在libvirt中当domain处于active状态时,修改最大内存时会报错,必须关闭domain再修改持久化配置。
在使用API开发虚机快照功能时,需要注意如下几点:
如果某虚机创建快照时使用的是内部快照或系统检查点,则该虚机所有硬盘都必须创建内部快照,qemu不支持创建混合快照,即一部分硬盘创建内部快照,一部分创建外部快照,当然只读盘如光驱默认是不创建快照的。
系统检查点默认所有可读写硬盘使用内部快照(关机状态下,会忽略disks标签内容)。
如果在创建快照方法中指定了flags为16(disk-only),则没有明确指定快照方式的硬盘默认使用外部快照,qemu目前不支持内外部混合快照。
使用系统检查点快照时,对cpu特性集有要求,当domain配置中cpu特性集有invtsc特性时,在domain运行时执行系统检查点快照会报错,解决办法,去掉invtsc特性或将cpu model改为custom。
当执行系统级快照时(开机状态下),如果配置文件标签制定snapshot=internal则硬盘快照默认也会使用internal方式执行,反之如果标签制定为external则硬盘默认也会使用external方式执行。这是因为qemu快照机制目前不支持内外部快照混合模式,libvirt内部机制会自动把硬盘快照方式调整为与内存相同方式。
使用外部快照要注意,执行外部快照文件是指向原硬盘快照(base 盘)的从镜像,执行完外部快照后,libvirt会将domain配置文件中的硬盘镜像改为新创建的外部快照文件,这样此文件可以用来存储执行快照后所有差异化内容,所以,libvirt不允许直接删除外部快照。 外部快照会与之前创建的外部快照形成一个差异存储链,内部快照不会与外部快照形成一个差异存储连。创建快照之后,快照配置文件会包含虚机配置文件的全部内容用于还原。
外部快照 内部快照
win7------------------------->win7_snap-------------------->win7_snap2(包含在win7_snap文件内部)
vm 外部 vm
|--------------------->win7_snap3
vm
win7是win7_snap的backingstore,win7_snap2快照存在于win7_snap文件中,win7_snap是win7_snap3的backingstore,内存外部快照可重复覆盖。 * 在关机状态下,执行任何快照,不能包含有内存状态,需要把内存snapshot设置为no,因为关机状态下没有内存运行状态,内存都清空了。 *创建系统检查点时,在关机状态下,默认创建内部快照,而且必须使用内部快照,创建外部快照会报错,但是使用disk-only模式快照,则在关机状态下允许创建外部快照同时也允许创建内部快照。外部快照声称的默认文件名称为原始硬盘镜像.快照名称 * 使用disk-only方式针对正在运行的虚机创建快照,必须使用external方式,并且标签的snapshot必须为no,使用内部快照会报错,内部快照和系统检查点快照要求所有硬盘都必须参与执行快照,使用disk-only和external方式并用执行快照才能针对不同硬盘单独执行快照策略。 * 使用系统检查点快照方式对处于active状态的虚机执行快照,快照生成的是内部还是外部取决于memory标签的snapshot值。 * 使用diskonly模式或关机状态下创建快照,标签snapshot必须为no,因为以上两种快照都无法保存内存状态。
各种快照模式及虚机状态的匹配情况:
1.虚机关机状态,diskonly模式:memory=no(必须),disk可以使用内部或外部快照,并且外部快照可以对每个盘分别定制创建策略,默认创建external快照。 2.虚机运行状态,diskonly模式:memory=no(必须),disk快照只能使用external模式创建,不支持创建内部快照。 3.系统检查点,虚机关闭状态:memory=no(必须),disk快照只能使用内部快照,而且是真对所有硬盘,无法针对每个盘定制快照创建策略。 4.系统检查点,虚机运行状态:memory=internal或external,disk快照的创建模式根据内存快照创建方式而定,不管内部还是外部快照都只能对所有硬盘创建快照,不支持对每个硬盘定制创建策略。 为什么快照机制这么混乱,因为libvirt和qemu对快照机制持有不同观点,但是那种观点更好,这是见仁见智的,我们可以根据情况选择使用。 ps:内部快照优点:不单独声称额外文件,没有存储连(其实是内部元数据,机制类似),降低了文件管理复杂度,libvirt对内部快照有良好支持。 ps:内部快照缺点:创建速度较慢,qemu上游较少维护,必须使用qcow2之类支持级联快照功能的文件格式。运行时创建快照虚机有明显停顿感。 ps:外部快照优点:创建速度较快,支持各种源文件格式(后续快照需使用qcow2之类),在运行时创建客户机几乎没有停顿时间,上游qemu在外部快照开发方面较积极 ps:外部快照缺点:快照多了后会形成大量存储文件及存储连,每一层级都使用cow方式读写,严重影响性能,文件管理复杂,libvirt对外部快照支持不太积极。
问答
内存快照,互斥特性很多,怎么在各阶段进行特性间的互斥?快照失败会回退吗?内存复用场景可以做快照吗?大规格内存快照时间规格大约多久?
答:快照建议根据我列出的特性进行选择,不建议把快照功能做得太多太复杂,快照多了会影响性能,如果必须要做外部快照,因为文件使用backingstore方式存储,最好对不用的快照进行commit,内存复用可以做快照,大规格内存做快照需要定制源码做优化,其实kvm虚拟化只是给我们一个基本功能,很多功能如果要满足客户需求需要对qemu和kvm源码进行定制开发。
SPICE有探测识别USB设备的功能吗?就是在宿主机的USB接口上插上USB设备之后,KVM虚拟机能够探测到吗?
答:spice的usb设备识别指的是将终端机上连接的设备识别为虚机上设备的功能,这是有spice的一个子功能usb redirect实现,至于宿主机外设,这是对qemu配置的问题。
免费提供最新Linux技术教程书籍,为开源技术爱好者努力做得更多更好:http://www.linuxprobe.com/