1、KVM发展历史
Kernel Virtual Machine,内核虚拟机。
最初由一个以色列的公司在2006年开发的一个开源项目,这个公司已经于2008年被RedHat所收购。
在RHEL5时代,Xen是RedHat公司集成和支持的虚拟机,而在2010年发布RHEL6开始至今,RedHat 公司使用KVM作为默认集成和支持的虚拟机工具。

目前的虚拟机技术阵营分成两个阵营,一类是以Xen,ESX/ESXi,Hyper-V为代表的微内核架构,系统上电之后首先加载的是虚拟机监控程序,虚拟机监控程序直接负责系统的初始化和物理资源的管理,创建、调度和管理虚拟机;另一类是以KVM,VMware Workstation, VirtualBox为代表,系统上电之后仍然首先加载运行的是一般意义上的操作系统,虚拟机监控程序只是这个操作系统之上的一个应用功能扩展。

  • KVM:是Linux完全原生的全虚拟化解决方案,就是在Linux内核中添加的一个虚拟机模块,直接使用Linux内核中已经完善的进程调度、内存管理与硬件设备交互等部分,使Linux成为一个可以支持运行虚拟机的Hypervisor。因此,KVM并不是一个完善的模拟器,而只是一个提供虚拟化功能的内核插件,它的具体的模拟器工作是借助工具(QEMU)来完成。
  • Xen:同时支持虚拟化与半虚拟化,需要在Linux系统内核之上再运行一个由Xen提供的微内核,由微内核控制虚拟化计算和内存资源的分配与使用 。因为诞生时间很早,那时硬件和系统内核层面根本没有支持虚拟化的,所以Xen被设计为不依赖也不使用硬件的虚拟化支持,通过对操作系统进行显式地修改(“移植”)以使其可以在Xen上作为虚机运行。

KVM需要CPU中虚拟化功能的支持,只可在具有虚拟化支持的CPU上运行,即具有VT功能的Intel CPU和具有AMD-V功能的AMD CPU。它包含一个为处理器提供底层虚拟化可加载的核心模块KVM.ko(KVM-intel.ko或KVM-AMD.ko)。KVM还需要一个经过修改的QEMU软件(qemu-KVM),作为虚拟机上层控制和界面。

KVM从Linux 2.6.20开始就已经被集成进入了Linux内核,可以说是与Linux内核一直在共同发展。而另一个明显有内核”不友好、不兼容“特点的Xen虚拟化方案一直无法得到Linux内核维护小组的支持。



2、KVM的架构原理

KVM是一个可以按需加载运行的Linux内核模块,仅支持硬件虚拟化,且KVM本身不做任何设备模拟,它是使用QEMU程序通过/dev/kvm接口进行I/O设备模拟。
KVM虚拟机的创建和运行就是一个用户空间的应用程序(QEMU)和KVM模块相互配合的过程。

QEMU,是一个独立发展的著名的开源虚拟机软件,并不是KVM的一部分。在QEMU中已经提供了虚拟机所需的整套技术实现,包括处理器虚拟化、内存虚拟化以及各类虚拟设备的模拟。但因为QEMU是一种纯软件解决方案,所以性能低下。

KVM定制了一个适合自己使用的QEMU版本,将用户空间程序负责的工作,例如虚拟机的创建、配置,虚拟机运行所依赖的虚拟设备,虚拟机运行时的用户操作环境和交互,甚至于虚机的动态迁移技术等,都交给QEMU所实现的。KVM自己仅作硬件虚拟化功能的实现。

命令方式创建KVM虚拟机
#virt-install --name centos6-test1 --ram 2048 --vcpus=2 --disk path=/data/images/centos6-test1.img,size=100 --network bridge=br0,model=virtio
 --accelerate --force --graphics vnc --autostart --noautoconsole --os-type=linux --os-variant=rhel6 --cdrom /root/CentOS-6.7-x86_64-minimal.iso

#virt-install -n win2008s -r 4096 --vcpus=2 --os-type=windows --accelerate -c /data/iso/Win2008R2Server_64bit.iso
 --disk path=/data/iso/virtio-win-0.1-100.iso,device=cdrom --disk path=/data/images/win2008x64.img,bus=virtio,size=60
 --network bridge=br0 --vnc --force --autostart

每个kvm虚拟机都是宿主机上的一个qemu进程
[bjxtb@MJQ_130_3 ~]$ ps -ef|grep kvm
root       2692      2  0  2016 ?        00:00:00 [kvm-irqfd-clean]
qemu      29478      1 99  2016 ?        479-15:25:54 /usr/libexec/qemu-kvm -name vm2 -S -M rhel6.6.0 -enable-kvm -m 48000
 -realtime mlock=off -smp 12,sockets=12,cores=1,threads=1 -uuid 61b7963d-477e-56b4-341a-0b86344cc04f -nodefconfig -nodefaults
 -chardev socket,id=charmonitor,path=/var/lib/libvirt/qemu/vm2.monitor,server,nowait -mon chardev=charmonitor,id=monitor,mode=control
 -rtc base=utc -no-shutdown -device ich9-usb-ehci1,id=usb,bus=pci.0,addr=0x5.0x7 -device ich9-usb-uhci1,masterbus=usb.0,firstport=0,
bus=pci.0,multifunction=on,addr=0x5 -device ich9-usb-uhci2,masterbus=usb.0,firstport=2,bus=pci.0,addr=0x5.0x1 -device ich9-usb-uhci3
,masterbus=usb.0,firstport=4,bus=pci.0,addr=0x5.0x2 -drive file=/var/lib/libvirt/images/vm2.img,if=none,id=drive-ide0-0-0,format=raw
,cache=none -device ide-drive,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0,bootindex=1 -netdev tap,fd=19,id=hostnet0 -device rtl8139,
netdev=hostnet0,id=net0,mac=52:54:00:24:8a:8c,bus=pci.0,addr=0x3 -chardev pty,id=charserial0 -device isa-serial,chardev=charserial0,
id=serial0 -vnc 127.0.0.1:1 -k en-us -vga cirrus -device intel-hda,id=sound0,bus=pci.0,addr=0x4 -device hda-duplex,id=sound0-codec0
,bus=sound0.0,cad=0 -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x6 -msg timestamp=on
root      29493      2  0  2016 ?        00:00:00 [kvm-pit-wq]
qemu      52222      1 14  2016 ?        34-07:57:55 /usr/libexec/qemu-kvm -name s3-vm1 -S -M rhel6.6.0 -enable-kvm -m 8192 -realtime mlock=off -smp 4,
sockets=4,cores=1,threads=1 -uuid a147b00b-cf4c-45e8-737b-5ad1066dc31b -nodefconfig -nodefaults -chardev socket,id=charmonitor,
path=/var/lib/libvirt/qemu/s3-vm1.monitor,server,nowait -mon chardev=charmonitor,id=monitor,mode=control -rtc base=utc -no-shutdown 
-device ich9-usb-ehci1,id=usb,bus=pci.0,addr=0x5.0x7 -device ich9-usb-uhci1,masterbus=usb.0,firstport=0,bus=pci.0,multifunction=on,
addr=0x5 -device ich9-usb-uhci2,masterbus=usb.0,firstport=2,bus=pci.0,addr=0x5.0x1 -device ich9-usb-uhci3,masterbus=usb.0,firstport=4,bus=pci.0,
addr=0x5.0x2 -drive file=/var/lib/libvirt/images/vm1.img,if=none,id=drive-ide0-0-0,format=raw,cache=none -device ide-drive,bus=ide.0,unit=0,
drive=drive-ide0-0-0,id=ide0-0-0,bootindex=1 -netdev tap,fd=23,id=hostnet0 -device rtl8139,netdev=hostnet0,id=net0,mac=52:54:00:62:f9:71,
bus=pci.0,addr=0x3 -chardev pty,id=charserial0 -device isa-serial,chardev=charserial0,id=serial0 -vnc 127.0.0.1:0 -k en-us -vga cirrus 
-device intel-hda,id=sound0,bus=pci.0,addr=0x4 -device hda-duplex,id=sound0-codec0,bus=sound0.0,cad=0 -device virtio-balloon-pci,
id=balloon0,bus=pci.0,addr=0x6 -msg timestamp=on


3、KVM的网络配置
3.1 网桥的使用
配置:
virsh iface-bridge eth0 br0
more ifcfg-br0
DEVICE=br0
ONBOOT=yes
BOOTPROTO=static
TYPE="Bridge"
IPADDR="172.17.90.15"
NETMASK="255.255.255.0"
GATEWAY="172.17.90.1"
DNS1="114.114.114.114"
STP="on"    
DELAY="0"

调优:
STP="on"     #打开生成树协议,避免出现环路
service NetworkManager stop
chkconfig NetworkManager off   #在RHEL/CENTOS系统中,NetworkManager服务无法管理网桥的配置,且会网络配置与生效产生干扰。

查看网桥:
$ brctl show
bridge name    bridge id        STP enabled    interfaces
br0        8000.2047478aa28c    yes             bond0
                                                vnet0
                                                vnet1
                                                vnet2
virbr0        8000.525400652d4c    yes        virbr0-nic


网桥virbr0是用于NAT网络模式使用的网桥

$ ifconfig virbr0
virbr0    Link encap:Ethernet  HWaddr 52:54:00:65:2D:4C 
          inet addr:192.168.122.1  Bcast:192.168.122.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 b)  TX bytes:0 (0.0 b)

$ ps -ef|grep dns
nobody     2396      1  0  2016 ?        00:00:00 /usr/sbin/dnsmasq --strict-order --pid-file=/var/run/libvirt/network/default.pid 
--conf-file= --except-interface lo --bind-interfaces --listen-address 192.168.122.1 --dhcp-range 192.168.122.2,192.168.122.254 
--dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases --dhcp-lease-max=253 --dhcp-no-override 
--dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile --addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts

# iptables -t nat -L -n
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         
Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
MASQUERADE  tcp  --  192.168.122.0/24    !192.168.122.0/24    masq ports: 1024-65535
MASQUERADE  udp  --  192.168.122.0/24    !192.168.122.0/24    masq ports: 1024-65535
MASQUERADE  all  --  192.168.122.0/24    !192.168.122.0/24   
Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

3.2 使用virtio-net

Virtio半虚拟化驱动的方式,可以获得很好的I/O性能,其性能几乎可以达到和native(即:非虚拟化环境中的原生系统)差不多的I/O性能。所以,在使用KVM之时,如果宿主机内核和客户机都支持virtio的情况下,一般推荐使用virtio达到更好的性能。

其中前端驱动(frondend,如virtio-blk、virtio-net等)是在客户机中存在的驱动程序模块,而后端处理程序(backend)是在QEMU中实现的。在这前后端驱动之间,还定义了两层来支持客户机与QEMU之间的通信。其中,“virtio”这一层是虚拟队列接口,它在概念上将前端驱动程序附加到后端处理程序。一个前端驱动程序可以使用0个或多个队列,具体数量取决于需求。例如,virtio-net网络驱动程序使用两个虚拟队列(一个用于接收,另一个用于发送),而virtio-blk块驱动程序仅使用一个虚拟队列。
虚拟队列实际上被实现为跨越客户机操作系统和hypervisor的衔接点,但它可以通过任意方式实现,前提是客户机操作系统和virtio后端程序都遵循一定的标准,以相互匹配的方式实现它。而virtio-ring实现了环形缓冲区(ring buffer),用于保存前端驱动和后端处理程序执行的信息。


3.3 关于vhost_net
这是宿主机中默认使用的虚拟机网络后端处理程序。在较新的Linux内核中已经集成作为一个驱动模块。当为KVM虚拟机选用virtio网络驱动模式时,后端即默认使用vhost_net。
$ lsmod|grep vhost _net
vhost_net              30520  3

$ ps -ef|grep vhost
bjxtb      3805   3346  0 16:32 pts/3    00:00:00 grep vhost
qemu       6508      1 99  2015 ?        578-08:41:17 /usr/libexec/qemu-kvm -name gate1-24 -S -M rhel6.6.0 -enable-kvm -m 32768 -realtime mlock=off
 -smp 12,sockets=12,cores=1,threads=1 -uuid bad75b87-6984-adb3-8946-db9f156afd03 -nodefconfig -nodefaults -chardev socket,id=charmonitor
,path=/var/lib/libvirt/qemu/gate1-24.monitor,server,nowait -mon chardev=charmonitor,id=monitor,mode=control -rtc base=utc -no-shutdown 
-device ich9-usb-ehci1,id=usb,bus=pci.0,addr=0x5.0x7 -device ich9-usb-uhci1,masterbus=usb.0,firstport=0,bus=pci.0,multifunction=on,addr=0x5
 -device ich9-usb-uhci2,masterbus=usb.0,firstport=2,bus=pci.0,addr=0x5.0x1 -device ich9-usb-uhci3,masterbus=usb.0,firstport=4,bus=pci.0
,addr=0x5.0x2 -drive file=/var/lib/libvirt/images/gate1-24.img,if=none,id=drive-virtio-disk0,format=raw,cache=none -device virtio-blk-pci,
scsi=off,bus=pci.0,addr=0x6,drive=drive-virtio-disk0,id=virtio-disk0,bootindex=1 -drive file=/var/lib/libvirt/images/gate1-24-1.img,
if=none,id=drive-ide0-0-0,format=raw,cache=none -device ide-drive,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0
 -drive file=/isotool/CentOS-6.5-x86_64-minimal.iso,if=none,media=cdrom,id=drive-ide0-1-0,readonly=on,format=raw -device ide-drive,bus=ide.1,unit=0,
drive=drive-ide0-1-0,id=ide0-1-0 -netdev tap,fd=22,id=hostnet0,vhost=on,vhostfd=23 -device virtio-net-pci,netdev=hostnet0,id=net0
,mac=52:54:00:e5:02:c3,bus=pci.0,addr=0x3 -chardev pty,id=charserial0 -device isa-serial,chardev=charserial0,id=serial0 -device usb-tablet,
id=input0 -vnc 127.0.0.1:0 -k en-us -vga cirrus -device intel-hda,id=sound0,bus=pci.0,addr=0x4 -device hda-duplex,id=sound0-codec0,bus=sound0.0,
cad=0 -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x7 -msg timestamp=on
root       6529      2 99  2015 ?        213557-03:59:26 [vhost-6508]

3.4 宿主机中的TSO、GSO配置
TSO,GSO是Linux中结合硬件实现的延迟大数据包拆分的技术,将原来由cpu负责的数据包拆分工作延迟至网卡上去完成,可以提升处理效率。
在KVM virtio网络虚拟化的实现中,有相关的案例中发现开启TSO,GSO功能后,反而会导致处理性能的下降。所以在这种情况下,可以人为得关闭这两个功能。
查看相关配置参数:
ethtool -k eth0
关闭TSO,GSO:
ethtool -K em1 gso off
ethtool -K em1 tso off


4、KVM性能
同等资源条件的物理机和KVM虚拟机,虚机的资源利用率相当于物理机的:
  • CPU  97%
  • Memory  95%
  • Network  除非是驱动设置有误,否则几乎相当,但相对于物理网卡会增加0.1ms的延时
  • disk  虚拟机的磁盘读写性能普遍上要低于物理机(数据块较小时差别明显,但当block size>1M时几乎无差别), 其中IDE驱动方式的性能又普遍低于virtio方式。如果采用磁盘的半虚拟化实现技术,则损失灵活性的同时,磁盘I/O性能会与物理机相当。                                                                                                                                                                                                           

5、centos6的KVM虚拟化安装方法
宿主机的系统安装要求:最小化安装,并使用yum -y update升级至centos6.8。

#安装KVM相关的依赖包和工具包
yum -y groupinstall  "Desktop" "X Window System"  chinese-support 'Virtualization' 'Virtualization Client' 'Virtualization Platform'
yum -y install kvm virt-viewer virt-manager bridge-utils tunctl libvirt libvirt-python python-virtinst

#查看和验证安装结果
service libvirtd status
lsmod |grep kvm

#使用xshell登录并验证KVM服务,需要能正常打开图形化的管理窗口
virt-manager

创建桥接网卡:
virsh iface-bridge bond0 br0
virsh iface-bridge bond1 br1

6、centos7的KVM虚拟化安装方法
宿主机的系统安装要求
centos7系统的KVM宿主机安装的软件包有以下:
@^gnome-desktop-environment
@base
@core
@directory-client
@fonts
@gnome-desktop
@guest-agents
@guest-desktop-agents
请确认在安装的软件包中包含了以上内容。

#停用系统可能自带和启用的NetworkManager
systemctl stop NetworkManager
systemctl disable NetworkManager

#安装kvm tools相关的工具包
yum -y groupinstall  'Virtualization' 'Virtualization Client' 'Virtualization Platform'

#调整centos7上ssh服务端口,设置为仅监听ipv4地址。否则会无法打开virt-manager图形窗口。
sed -i 's/#AddressFamily any/AddressFamily inet/g' /etc/ssh/sshd_config
systemctl restart sshd

#使用xshell登录并验证KVM服务,需要能正常打开图形化的管理窗口
virt-manager













Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐