《KVM虚拟化技术:实战与原理解析》作者写作过程草稿连载http://smilejay.com/kvm_theory_practice/
KVM简介
与xen开发了一套从VCPU调度到内存管理一应俱全的底层操作系统不同,Kernel-Based Virtual Machine是基于kernel的虚拟机,完全利用Linux内核来实现CPU的调度,内存管理的功能。KVM只能运行在支持硬件虚拟化的CPU上。
KVM核心层仅有3个内核模块:kvm,kvm_intel和kvm_amd(分别对应Intel和AMD的CPU);kvm驱动负责创建虚拟机,为vcpu注入中断和提供时钟信号,使用KVM的io_ctl接口可以管理vcpu和vm。
KVM开发者选择了已经成型的开源虚拟化软件QEMU作为用户层管理Guest OS的接口。Qemu实现了I/O设备模拟,提供访问外设的途径。这种架构使得KVM避免了繁琐的设备模拟和设备驱动(内核中80%以上的代码就是驱动部分)。QEMU除了是一款虚拟化软件以外还是一款仿真器,它可以模拟多种不同的CPU和平台,例如x86,Power PC,S390 guest(IBM的一种大型机)经由kqemu这个开源的加速器,QEMU能模拟至接近真实电脑的速度。
KVM架构
使用modprobe命令装载KVM模块后,Linux内核就成为了一个hypervisor,并且在Linux原有的Kernel mode和User mode的基础上,新增加了Guest mode,Guest mode拥有自己的Kernel mode和User mode。在KVM模型中,每一个Gust OS都是作为一个标准的Linux进程,都可以使用Linux进程管理命令管理。在虚拟机运行时,三种模式的工作各为:
KVM 工作原理
User mode Qemu利用libkvm通过ioctl进入Kernel mode,kvm模块为Guest OS创建Virtual Memory,VCPU,然后执行VMLAUCH指令进入Guest mode,加载Guest OS并执行。如果Guest OS发生外部中断或者影子页表缺页之类的情况,会暂停Guest OS的执行,退出Guest mode进行异常处理,之后重新进入Guest mode,执行客户代码。如果发生I/O事件或者信号队列中有信号到达,就会进入User mode 处理。
libvirt
libvirt是为了安全高效的管理节点上的各个域,而提供一个公共的稳定的软件层。它是目前使用最为广泛的对KVM虚拟机进行管理的工具和应用程序接口(API),而且一些常用的虚拟机管理工具(如virsh、virt-install、virt-manager等)和云计算框架平台(如OpenStack、OpenNebula、Eucalyptus等)都在底层使用libvirt的应用程序接口。
libvirt对多种不同的Hypervisor的支持是通过一种基于驱动程序的架构来实现的。libvirt对不同的Hypervisor提供了不同的驱动:对Xen有Xen的驱动,对QEMU/KVM有QEMU驱动,对VMware有VMware驱动。
libvirt作为中间适配层,让底层Hypervisor对上层用户空间的管理工具是可以做到完全透明的,因为libvirt屏蔽了底层各种Hypervisor的细节,为上层管理工具提供了一个统一的、较稳定的接口(API)。通过libvirt,一些用户空间管理工具可以管理各种不同的Hypervisor和上面运行的客户机,它们之间基本的交互框架如下图所示。
在libvirt中涉及到几个重要的概念,解释如下:
KVM管理工具有两组libvirt和Qemu
virtio
http://www.ibm.com/developerworks/cn/linux/1402_caobb_virtio/
Virtio是对半虚拟化hypervisor中的一组通用模拟设备的抽象,virtio由Rusty Russell 开发,他当时的目的是支持自己的虚拟化解决方案 Lguest。Virtio该设置还允许hypervisor导出一组通用的模拟设备,并通过一个通用API让它们变得可用。有了半虚拟化hypervisor之后,Guest OS能够实现一组通用的接口,在一组后端驱动程序之后采用特定的设备模拟。后端驱动程序不需要是通用的,因为它们只实现前端所需的行为。
下面基于VMware上CentOS6.4_X86_64安装KVM软件包组,并是否可以启动测试一个微型Linux系统
安装KVM,KVM是第一个整合到Linux主线内核的虚拟化技术(从2.6.20开始),红帽收购了KVM,旗下的虚拟化业务也由XEN向KVM转移。
KVM使用了QEMU的一部分,并稍加改造,就成了可控制KVM的用户空间工具了。所以官方提供的KVM下载有两大部分(qemu和kvm)三个文件(KVM模块、QEMU工具以及二者的合集)。
[root@DQ ~]# yum groupinstall " Virtualization" "Virtualization Client" " Virtualization Platform"
libvirtd 是一个作为 libvirt 虚拟化管理系统中的服务器端的守护程序,如果要让某个节点能够用 libvirt 进行管理(无论是本地还是远程管理),都需要在这个节点上运行着 libvirtd 这个守护进程,以便让其他上层管理工具可以连接到该节点,libvirtd 负责执行其他管理工具发送它的虚拟化管理操作指令。而 libvirt 的客户端工具(包括virsh、virt-manager等)可以连接到本地或远程的 libvirtd 进程,以便管理节点上的客户机(启动、关闭、重启、迁移等)、收集节点上的宿主机和客户机的配置和资源使用状态。
[root@DQ ~]# service libvirtd start
[root@DQ ~]# chkconfig libvirtd on
使用virt-install创建虚拟机并安装GuestOS
virt-install是一个命令行工具,它能够为KVM、Xen或其它支持libvrit API的hypervisor创建虚拟机并完成GuestOS安装;此外,它能够基于串行控制台、VNC或SDL支持文本或图形安装界面。安装过程可以使用本地的安装介质如CDROM,也可以通过网络方式如NFS、HTTP或FTP服务实现。对于通过网络安装的方式,virt-install可以自动加载必要的文件以启动安装过程而无须额外提供引导工具。当然,virt-install也支持PXE方式的安装过程,也能够直接使用现有的磁盘映像直接启动安装过程。
virt-install命令有许多选项,这些选项大体可分为下面几大类,同时对每类中的常用选项也做出简单说明。
一般选项:指定虚拟机的名称、内存大小、VCPU个数及特性等;
安装方法:指定安装方法、GuestOS类型等;
存储配置:指定存储类型、位置及属性等;
–disk=DISKOPTS:指定存储设备及其属性;
格式为–disk /some/storage/path,opt1=val1,opt2=val2等;常用的选项有:
网络配置:指定网络接口的网络类型及接口属性如MAC地址、驱动模式等;
-w NETWORK, –network=NETWORK,opt1=val1,opt2=val2
将虚拟机连入宿主机的网络中,其中NETWORK可以为:
其它常用的选项还有:
图形配置:定义虚拟机显示功能相关的配置,如VNC相关配置;
设备选项:指定文本控制台、声音设备、串行接口、并行接口、显示接口等;
虚拟化平台:虚拟化模型(hvm或paravirt)、模拟的CPU平台类型、模拟的主机类型、hypervisor类型(如kvm、xen或qemu等)以及当前虚拟机的UUID等;
其它:
尽管virt-install命令有着类似上述的众多选项,但实际使用中,其必须提供的选项仅包括–name、–ram、–disk(也可是–nodisks)及安装过程相关的选项。此外,有时还需要使用括–connect=CONNCT选项来指定连接至一个非默认的hypervisor。
virsh uri:查看当前主机上hypervisor的连接路径;可以使用virsh connect命令连接
下面这个示例创建一个名为self-made的虚拟机,因为实验环境在VMware中,没有硬件支持,所以指定hypervisor为qemu,内存大小为512MB,磁盘为80G的映像文件/var/lib/libvirt/images/selfmade.img,通过boot.iso光盘镜像来引导启动安装过程。
说明:boot.iso是我之前基于rhel5.4制作的,功能没有完全,在VMware上直接引导启动时可以进行到Loading achi driver这一步,而后镜像在使用过程中会断开连接
单击虚拟机界面右下角光盘的图标,选择连接,然后返回安装界面点OK,进行安装又会自动断开连接,目前还不知道是哪里出错
下面先用这个不完整的boot.iso做测试,看kvm是否可以启动
在上述步骤中敲下Enter键,引导止步于
Loading vmlinuz…………………………..
Loading initrd.img…………………………………………………
Ready.
执行以下命令可以发现self-made已经运行
下面创建虚拟磁盘文件,而后格式化挂载分别作为Guest OS的/boot和/,制作一个微型Linux系统测试kvm能否启动
[root@DQ ~]# mkfs.ext4 /dev/mapper/loop0p1
[root@DQ ~]# mkfs.ext4 /dev/mapper/loop0p2
安装grub,为其提供vmliuz和initramfs.img,grub安装时没有模拟出来BIOS设备
将/sbin/init的任务精简,复制二进制程序运行依赖的系统库文件到虚拟磁盘映像文件挂载点/mnt中对应的路径下;提供/sbin/init运行需要的配置文件rcS.conf以及配置文件依赖于的脚本/etc/rc.d/rc.sysinit
安装一个名为CentOS6.4的虚拟机,直接导入
由上图可知测试止步于Booting……(从磁盘引导)可能由于实验环境是在VMware中,强行基于Qemu创建虚拟机对于kvm来说可能有些难度,目前我还不是太清楚
virsh define: 创建一个虚拟机,根据事先定义的xml格式的配置文件;创建以后不会自动启动;
virsh create: 创建一个虚拟机,创建完成后会自动启动;
virsh undefine: 删除一个虚拟机
每个虚拟机创建后,其配置信息保存在/etc/libvirt/qemu目录中,文件名与虚拟机相同,格式为XML
下面的示例将创建一个名为rhel6的虚拟机,其有两个虚拟CPU,安装方法为FTP,并指定了ks文件的位置,磁盘映像文件为稀疏格式,连接至物理主机上的名为brnet0的桥接网络:
# virt-install \
--connect qemu:///system \
--virt-type kvm \
--name rhel6 \
--ram 1024 \
--vcpus 2 \
--network bridge=brnet0 \
--disk path=/VMs/images/rhel6.img,size=120,sparse \
--location ftp://172.16.0.1/rhel6/dvd \
--extra_args “ks=http://172.16.0.1/rhel6.cfg” \
--os-variant rhel6 \
--force
下面的示例将创建一个名为rhel5.8的虚拟机,磁盘映像文件为稀疏模式的格式为qcow2且总线类型为virtio,安装过程不启动图形界面(–nographics),但会启动一个串行终端将安装过程以字符形式显示在当前文本模式下,虚拟机显卡类型为cirrus:
# virt-install \
--connect qemu:///system \
--virt-type kvm \
--name rhel5.8 \
--vcpus 2,maxvcpus=4 \
--ram 512 \
--disk path=/VMs/images/rhel5.8.img,size=120,format=qcow2,bus=virtio,sparse \
--network bridge=brnet0,model=virtio
--nographics \
--location ftp://172.16.0.1/pub \
--extra-args "ks=http://172.16.0.1/class.cfg console=ttyS0 serial" \
--os-variant rhel5 \
--force \
--video=cirrus
下面的示例则利用已经存在的磁盘映像文件(已经有安装好的系统)创建一个名为rhel5.8的虚拟机:
# virt-install \
--name rhel5.8
--ram 512
--disk /VMs/rhel5.8.img
--import