KVM学习笔记总结

1.虚拟化种类:
1.1 纯软件虚拟化(QEMU:解析所有指令并仿真处理,VMWare workstation:使用动态二进制翻译技术,虚拟机可以在可控的范围内直接运行在物理平台上,但是在那之前会的被扫描一遍要运行的指令,对于一些敏感的指令会的进行相关处理)
1.2硬件虚拟化(需要CPU支持。就是捕获trap,比如Intel的IntelVT技术)
1.3准虚拟化(也叫半虚拟化,对客户机操作系统的源代码进行一定的修改,如Xen)

1.4全虚拟化(不需要对OS进行任何的修改,具有无可比拟的优势。主要的产品有VMware ESX,Virtual Box(它也支持纯软件虚拟化))

2.Xen简介
一个准虚拟化的平台,之所以流行主要是因为以前CPU不支持虚拟化技术。

3.KVM简介
全称Kernel Virtual Machine。老爹是RedHat,因此在RHEL 6中默认就是KVM,取代了之前的Xen。
KVM是基于Intel VT或AMD-V的X86平台的,完全原生的全虚拟化解决方案。同时对于一些特定的设备,提供准虚拟化支持。是Linux发行版的标准组件。是Linux的几个模块。
在KVM的架构中,虚拟机的实现(或者说每个CPU)都是常规的Linux的进程。由标准的Linux调度程序进行调度。但是KVM本身不提供任何的模拟(比如IO设备啥的就没有),因此要使用QEMU来模拟其显示器等。

4.KVM模块和QEMU
KVM模块是KVM的核心。其和QEMU相辅相成。QEMU模拟通过KVM达到了硬件虚拟化的速度,而KVM则通过QEMU来模拟设备。
现在所说的虚拟化,一般都是指在CPU硬件支持基础之上的虚拟化技术。KVM也同hyper-V、Xen一样依赖此项技术。没有CPU硬件虚拟化的支持,KVM是无法工作的。准 确来说,KVM是Linux的一个模块。可以用modprobe去加载KVM模块。加载了模块后,才能进一步通过其他工具创建虚拟机。但仅有KVM模块是远远不够的,因为用户无法直接控制内核模块去作事情:还必须有一个用户空间的工具才行。这个用户空间的工具,开发者选择了已经成型的开源虚拟化软件QEMU。说起来QEMU也是一个虚拟化软件。它的特点是可虚拟不同的CPU。比如说在x86的CPU上可虚拟一个Power的CPU,并可利用它编译出 可运行在Power上的程序。KVM使用了QEMU的一部分,并稍加改造,就成了可控制KVM的用户空间工具了。所以你会看到,官方提供的KVM下载有两大部分三个文件,分别是KVM模块、QEMU工具以及二者的合集。也就是说,你可以只升级KVM模块,也可以只升级QEMU工具。这就是KVM和QEMU 的关系。

说的简单点,KVM只模拟CPU和内存,因此一个OS可以在上面跑起来,但是你看不到他,无法和他沟通。于是有人修改了QEMU的代码,把它模拟CPU、内存的代码换成KVM,而网卡、显示器啥的留着。因此QEMU+KVM就成了一个完整的虚拟化平台。

5.查看KVM是否安装的两个方法

[root@RHEL65 ~]# ls /dev/kvm 
/dev/kvm
[root@RHEL65 ~]# lsmod | grep -i kvm
kvm_intel              54285  0 
kvm                   333172  1 kvm_intel

如果没有安装,那么:

yum install kvm kmod-kvm qemu kvm-qemu-img virt-viewer virt-manager libvirt libvirt-python python-virtinst
service libvirtd start
chkconfig libvirtd on

6.VNC
如果要启用VNC,那么编译qemu-kvm的时候就要注意相关的开关。然后启动的时候用下面的命令:
[root@RHEL65 kvm_demo]# qemu-system-x86_64 -m 512 -smp 1 -hda /root/kvm_demo/rhel6u5.img -vnc 192.168.19.105:1
这里的端口号是:后面的数字+5900,也就是5901

7.一次最简单的启动(注意这里要加-enable-kvm,默认的话是软解析的,很慢)

[root@RHEL65 kvm_demo]# qemu-system-x86_64 -m 700 -boot order=dc -smp 1 -hda /root/kvm_demo/rhel6u5.img -cdrom /root/Desktop/rhel-server-6.5-x86_64-dvd.iso -vnc 192.168.19.105:1 -enable-kvm

8.判断是否使用了KVM
如果你怀疑你没有启用KVM提供的硬件加速功能。你可以按照下面的步骤做检查。首先,看看你有没有得到下面的提示信息:

qemu-system-x86_64 -hda myvm.qcow2
open /dev/kvm: No such file or directory
Could not initialize KVM, will disable KVM support

如果是这种情况,请再检查:
1. kvm模块被正确载入了吗? lsmod | grep kvm.
2. 查看 dmesg 的输出,保证没有这个提示信息: “KVM, disabled by BIOS”.
3. 请确保/dev/kvm 确实存在,而且你有权限使用它。

其它诊断方式:
1. 如果你能使用 QEMU monitor ( ctrl-alt-2, 再 ctrl-alt-1 回到 VM 的显示屏 ),敲入 info kvm 命令。如果正常的话,应该有“KVM support: enabled”这条信息输出。 ###我推荐用这个
2. 在host机上敲 lsmod | grep kvm 命令,看看输出的最右栏。如果kvm在正常运行的话,这个数字不能是0。这行的数字与架构相关的模块(一般指的是kvm_intel,或kvm_amd)有联系,它显示了有多少个VM正在使用这个模块。举例说明,如果你有两个虚拟机正在使用KVM模块,host机的CPU使用的是vt技术,那么就会得到:

# lsmod | grep kvm
kvm_intel              44896  2
kvm                   159656  1 kvm_intel

9.CPU
一个vCPU就是一个QEMU的线程,可以通过ps -efL | grep qemu查看。
可以在启动qemu的时候加上对应的参数来设置CPU个数,如:

[root@RHEL65 libexec]# qemu-system-x86_64 -smp 2,sockets=2,cores=2,threads=2

之后在vm里通过cat /proc/cpuinfo或在QEMU monitor中运行info cpus可以查看vm的CPU信息。

推荐对多个使用单个CPU的VM进行过载,但不推荐vCPU个数大于CPU个数。在负载较重的生产中尽量还是不要过载了。

CPU模型:就是CPU的类型,可以通过qemu-system-x86_64 -cpu ?查看。

配合taskset工具,可以设置CPU的亲和性。

如果要支持嵌套虚拟化,需要加上-cpu host或-cpu qemu64,+vmx(qemu64可以换成各种model)

10,内存
通过-m指定内存的大小,单位是MB
注意,除非特别指定,否则KVM不会在启动的时候立马分配所有内存。

通过-mem-path可以挂载hugepage,通过-mem-prealloc可以让kvm在启动的时候就分配指定数量的内存

内存过载:
一般有三个技术可以实现:
1.通过交换分区
2.通过virio_balloon驱动
3.通过内存页共享
内存过载的话一般第一个比较成熟,但效率也最低。由于KVM是一个进程,因此只有在这个进程请求更多内存的时候内核才会分配内存给它。所以宿主机只要有足够的交换空间,那么是可以过载的。但物理内存+交换空间的大小只和需要大于内置给所有客户虚拟机的内存只和。

11.存储配置
主要参数(如果直接指定file而不加参数,就是-hda):
-hda:第一个IDE设备,可以是个文件,也可以是真是的物理硬盘(如-hda /dev/sdb),在KVM里看到的是/dev/hda或/dev/sda
-hdb:第二个IDE设备
-hdc:第三个IDE设备
-hdd:第四个IDE舍必
-fda:第一个软盘,在KVM里是/dev/fd0
-fdb:第二个软盘
-cdrom:CD-ROM,在KVM里是/dev/cdrom,也可以直接将宿主机的cdrom拿来用,命令是-cdrom /dev/cdrom,不过不能和-hdc合用,因为KVM中的-hdc就是cdrom
-mtblock:Flash存储器的模拟
-sd:SD卡的模拟
-pflash:并行Flash存储器的模拟

新版本的QEMU可以用-drive详细的定义一个驱动器,几个常见的参数有:
file=XXX
if=XXX:XXX可以是ide/scsi/virtio等,指明驱动器类型
snapshot=on/off:是否启用snapshot。如果设置为on,那么KVM不会的将对这个drive的修改写入对应文件中去,而是写入到临时文件中,除非在qemu monitor中强制执行commit
cache=none/off/writeback/writethrough:none和off一样,读写都不走cache,writeback和writethrough读都走cache,写的话writeback写入cache就ok,而writethrough要写入块设备才ok,所以writethrough很慢。
readonly=on/off:是否只读

指定启动顺序:
-boot参数。在QEMU中,a、b表示第一和第二个软驱,c表示第一个硬盘,d表示CDROM,n表示网络启动。默认就是abcdn的顺序
用法是:
-boot order=c:每次重启都从c启动
-boot once=c:第一次是从c启动,之后都是默认顺序
-boot order=dc,menu=on:默认启动是d和c的顺序,并且打开交互式启动菜单选项

一个例子:

[root@RHEL65 kvm_demo]# qemu-system-x86_64 -m 1024 -smp 2 -drive file=/root/kvm_demo/rhel6u5.bf.img,cache=writeback,if=ide  -vnc 192.168.19.105:1 -enable-kvm

12.qemu-img
QEMU的磁盘管理工具,主要用法有:
qemu-img check XXX:检测image是否有问题,支持qcow2/qed/vdi格式
qemu-img info XXX:查看image信息

[root@RHEL65 kvm_demo]# qemu-img info rhel6u5.img 
image: rhel6u5.img
file format: raw
virtual size: 7.8G (8388608000 bytes)
disk size: 7.8G

创建磁盘:

[root@RHEL65 kvm_demo]# qemu-img create -f qcow2 rhel6u5.img 8G

还可以使用它做调整image大小、查看image中的快照、转换image格式、对image进行加密等等很多的操作。

可以用qemu-img -h查看支持的image格式,一般推荐是qcow2

这里来看一个东西:后端镜像文件,比如我已经有一个安装好所有东西的image A,然后我想给5个客户用,那么他们的image B/C/D/E/F都可以以image A为source,通过qemu-img建立的image B/C/D/E/F的初始化大小为0,如果客户B修改了A中的东西,那么image B就会的仅仅记录修改的东西,而不影响A:

[root@RHEL65 kvm_demo]# ll
total 11955228
drwxr-xr-x 50 root root      20480 Mar 24 07:53 qemu-kvm.git
-rw-r--r--  1 root root 8388608000 Mar 25 04:59 rhel6u5.img
-rwxrw-rw-  1 root root 3853516800 Jan 26 02:48 rhel-server-6.5-x86_64-dvd.iso
[root@RHEL65 kvm_demo]# qemu-img create -f qcow2 -o backing_file=/root/kvm_demo/rhel6u5.img,size=10G rhel6u5.bf.img
Formatting 'rhel6u5.bf.img', fmt=qcow2 size=10737418240 backing_file='/root/kvm_demo/rhel6u5.img' encryption=off cluster_size=65536 lazy_refcounts=off 
[root@RHEL65 kvm_demo]# ll
total 11955424
drwxr-xr-x 50 root root      20480 Mar 24 07:53 qemu-kvm.git
-rw-r--r--  1 root root     197120 Mar 26 05:54 rhel6u5.bf.img #############是以rhel6u5.img为源的一个image
-rw-r--r--  1 root root 8388608000 Mar 25 04:59 rhel6u5.img
-rwxrw-rw-  1 root root 3853516800 Jan 26 02:48 rhel-server-6.5-x86_64-dvd.iso

13.网络配置
先看两个概念:
TUN与TAP是操作系统内核中的虚拟网络设备。不同于普通靠硬件网路板卡实现的设备,这些虚拟的网络设备全部用软件实现,并向运行于操作系统上的软件提供与硬件的网络设备完全相同的功能。
TAP 等同于一个以太网设备,它操作第二层数据包如以太网数据帧。TUN模拟了网络层设备,操作第三层数据包比如IP数据封包。

注意,QEMU的VLAN不是通常意义上的802.1Q的VLAN。如果要实现802.1Q的VLAN,需要配合vconfig来实现bridge的流量forwarding。

QEMU提供了4种网络模式(除了第四种,其它都是通过-net参数配置的。默认的参数是-net nic -net user):
1.基于brige
2.基于NAT
3.QEMU内置的用户模式网络
4.直接分配网络设备的网络

查看支持的网卡种类:

[root@RHEL65 kvm_demo]# qemu-system-x86_64 -net nic,model=?
qemu: Supported NIC models: ne2k_pci,i82551,i82557b,i82559er,rtl8139,e1000,pcnet,virtio

基本-net参数:
-net nic:必须的参数
vlan=n:指定VLAN,默认是0
macaddr=XXX:指定mac地址
model=XXX:指定虚拟的型号
name=XXX:指定网卡名字,在QEMU monitor中有用
addr=XXX:指定PCI相关的ADDR
vectors=XXX:在virtio中有用

客户机中通过下面的一些命令查看网卡信息:
lspci | grep Eth
ethtool -i eth1
ifconfig
(qemu) info network

下面详细看看各种模式:
1.网桥模式:
通过-net tap来配置,相关参数有:
vlan=n:指定vlan,默认是0
nam=XXX:QEMU monitor中看到的名字
ifname=XXX:在宿主机中添加的TAP虚拟设备的名字
script=fileXXX:在KVM启动的时候,在宿主机中自动执行的脚本
downscript=fileXXX:在KVM关闭的时候,在宿主机中自动执行的脚本

如果要使用这种模式,需要安装下面两个包:
yum install bridge-utils tunctl
查看tun的模块是否加载:
[root@RHEL65 kvm_demo]# lsmod | grep tun
tun 17095 2 vhost_net

一个简单例子:
宿主机的一个简单配置:

[root@RHEL65 Desktop]# brctl addbr br0
[root@RHEL65 Desktop]# brctl addif br0 eth0
[root@RHEL65 Desktop]# brctl stp br0 on   #打开STP协议,否则可能造成环路
[root@RHEL65 Desktop]# ifconfig eth0 0
[root@RHEL65 Desktop]# dhclient br0  #动态给br0配置ip、route等,也可以手动配置。这里可以想象成eth0已经没用了,功能全部由br0这个网桥设备(或者可以假想成一个虚拟网卡)来代替。宿主机的应用要上网的话,可能要通过一个网卡,既然eth0没用了,那么就得走br0了,于是默认GATEWAY的出口interface啥的都会的走br0,br0收到后应该会的forwarding,然后从eth0出去。所以个人感觉宿主机现在是有一块br0的网卡,当要和外界通信的时候,肯定是send_packet(br0,XXX),把数据从br0这个虚拟网卡发出去。而br0连接在了虚拟交换机上,eth0也在里边,于是从eth0转发出去了,就好像直接从br0转发出去了一样。同时,由于br0连在了虚拟交换机上,所以虚拟交换机上的KVM应该可以ping通它。那如果我想要和外网通信,并且想用eth0应该咋办呢?很简单,把eth0配成默认的gateway的出口,并给个IP就行了。
[root@RHEL65 Desktop]# route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
192.168.19.0    *               255.255.255.0   U     0      0        0 br0
192.168.122.0   *               255.255.255.0   U     0      0        0 virbr0
default         promote.cache-d 0.0.0.0         UG    0      0        0 br0

准备启动脚本,功能是在KVM启动的时候把它的虚拟网卡加入到br0中去:

[root@RHEL65 kvm_demo]# cat qemu-ifup 
#!/bin/bash
switch=br0

if [ -n "$1" ]; then
    #tunctl -u ${whoami} -t $1
    ip link set $1 up
    sleep 1
    brctl addif ${switch} $1
    exit 0
else
    echo "Error: no interface specified"
    exit 1
fi

准备结束脚本,一般不用做这个,应为QEMU会自动做:

[root@RHEL65 kvm_demo]# cat qemu-ifdown 
#!/bin/bash
switch=br0

if [ -n "$1" ];then
    tunctl -d $1
    brctl delif ${switch} $1
    ip link set $1 down
    exit 0
else
    echo "Error: no interface specified"
    exit 1
fi

一定要赋予可执行权限:

[root@RHEL65 kvm_demo]# chmod a+x qemu-if*

先看一下此时的br0的状态:

[root@RHEL65 kvm_demo]# brctl show 
bridge name bridge id       STP enabled interfaces
br0     8000.000c296b6bd5   yes     eth0
pan0        8000.000000000000   no      
virbr0      8000.5254008cec79   yes     virbr0-nic

启动一个KVM:

[root@RHEL65 kvm_demo]# qemu-system-x86_64 rhel6u5.bf.img -smp 2 -m 1024 -net nic -net tap,ifname=tap1,script=/root/kvm_demo/qemu-ifup,downscript=no -vnc 192.168.19.193:1 -enable-kvm

再次查看br0状态,发现tap1出来了,ifconfig也可以看到tap1了:

[root@RHEL65 ~]# brctl show
bridge name bridge id       STP enabled interfaces
br0     8000.000c296b6bd5   yes     eth0
                            tap1
pan0        8000.000000000000   no      
virbr0      8000.5254008cec79   yes     virbr0-nic

这个时候在KVM里可以看到有一个eth0的网卡,给他配个IP后就可以ping通内网了(当然也能ping通插在br0上的br0网卡了)。
当把KVM关了的时候,直接就会删除tap1这个设备,br0中的那个tap1也会被删除。

2.NAT模式
补充一个小技巧:如果外网要访问内网的IP,可以在防火墙上做些设置,把NAT服务器的某个port映射到内网IP上。这样对某个端口的访问就可以映射到对内网的某个端口的访问了。

其原理也很简单,比如我们的KMV网络都连在一个br1上,这个br1上没有任何的物理网口,但是br1这个虚拟网卡插在上面。我们把这个br1的虚拟网卡配置一个IP,作为默认的网关,于是KVM虚机的网络就能PING通这个br1了,但是他们的IP从哪里来呢?由于br1是个虚拟网卡,有IP,所以我们跑dhcp的服务dnsmasq(虽然名字里有dns,但功能貌似是dhcp)在这个br1的IP上,KVM里的网卡通过DHCP请求从br1虚拟交换机上的br1虚拟网卡上运行的dnsmasq服务就能获得IP了。另外dnsmasq也能做NAT,所以我KVM的默认路由设成br1,那么我就能通过这个br1和外界沟通了。当然在iptables上还有很多要设置的。

所以在nat这里启动脚本就比较复杂了,要判断dnsmasq是否运行,没有运行的话要运行,然后把tap设备加入到相应的br里,然后设置iptables等。另外KVM里获取IP就不用手工配置了,通过dhclient来获取。我们来看看这个怎么弄:
相关的两个脚本参考notes中的文件:

[root@RHEL65 kvm_demo]# qemu-system-x86_64 rhel6u5.bf.img -smp 2 -m 1024 -net nic -net tap,ifname=tap1,script=/root/kvm_demo/qemu-ifup-NAT,downscript=/root/kvm_demo/qemu-ifdown-NAT -vnc 192.168.19.193:1 -enable-kvm

我们可以看到新建立的natbr0已经起来了,并且只有tap1在里边:

[root@RHEL65 ~]# brctl show
bridge name bridge id       STP enabled interfaces
br0     8000.000c296b6bd5   yes     eth0
natbr0      8000.a2db142023d1   yes     tap1
pan0        8000.000000000000   no      
virbr0      8000.5254008cec79   yes     virbr0-nic

natbr0这个虚拟网卡的ip是:

natbr0    Link encap:Ethernet  HWaddr A2:DB:14:20:23:D1  
          inet addr:192.168.122.1  Bcast:192.168.122.255  Mask:255.255.255.0
          inet6 addr: fe80::5075:a3ff:feb6:85d3/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:6 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:0 (0.0 b)  TX bytes:468 (468.0 b)

tap1所在的KVM的网卡eth0通过二层协议,通过广播可以获取自己的IP以及其它信息(通过dhclient eth0命令)。

对于这里的KVM,NAT就是GATEWAY所在的主机(也就是虚拟网卡natbr0),如果natbr0上面运行了DNS服务,那么可以把KVM的DNS配成natbr0,否则配成natbr0所在的宿主机的DNS即可,后者通过NAT是可以访问的。

3.QEMU内部的用户模式网络
默认就是-net nic -net user这个配置。该网络完全由QEMU自己实现,不依赖于bridge-utils/dnsmasq等工具,QEMU自己实现了一整套TCP/IP协议栈。

在新版本的QEMU中,使用-netdev参数替代上面的参数了。功能上有所加强,但上面的这些都能实现。

14.图形显示
1.SDL
QEMU默认使用SDL这个多媒体程序库来实现图形。如果QEMU要使用这个,需要在编译的时候安装SDL-devel这个包,然后设置编译该模块才行。
但SDL也有一定局限,其在启动QEMU的时候必定要弹出一个图形框框,所以如果你用的是SSH等字符工具,则无法看到这个框框,就会报错。
其样子其实和VMWare差不多,鼠标通过Ctrl+Alt来切换。

2.VNC
如果不使用QEMU自带的VNC功能,那么:
安装对应server服务:
[root@RHEL65 ~]# yum install tigervnc-server
然后通过vncserver :1这样的命令运行VNC。

如果使用QEMU自带的VNC功能,那么就可以把VGA的显示输出到VNC会话中而不是SDL中了。
可以在QEMU monitor中修改VNC的配置。命令是change vnc :2这类。

另外keymap要用en-us的。

通过文本直接输出到屏幕:
可以有两个选择:修改客户机的grub文件,做一个重定向,然后加上-nographic参数。或者宿主机安装curses或ncurses这样的软件包,编译QEMU的时候enable,然后加-curses选项。

15.半虚拟化驱动
KVM对内存、CPU都收硬件虚拟化的,但对于IO等设备,由于使用了QEMU,他们都是通过软件来模拟的,因此性能很低。virtio就是为了解决这个而产生的。
virtio需要hipervisor意识到。因此KVM知道自己用的是virtio。同时客户机需要有特定的virtio驱动的支持。RHEL 6版本之后默认都有这个的驱动,而windows则需要单独安装。一般是yum install virtio-win,然后就可以在/usr/share/virtio-win中找到一大堆的驱动,然后上传到客户机中进行安装。

查看RHEL客户机是否安装相关驱动:

[root@RHEL65 kvm_demo]# find /lib/modules/2.6.32-431.el6.x86_64/ -name "virtio*.ko"

也可以查看客户机使用使用了相关模块:lsmod | grep virtio

下面来具体看看各种virtio都能干些啥:
1.ballooning
在虚拟机运行的时候动态改变其内存。
在KVM中的原理是:
KVM发送请求给客户机,让其归还一定的内存。客户机中的virtio_balloon驱动收到请求后进行相关操作,把内存给其他客户机使用。(比如我给了KVM 2G的内存,实际上只用了512M,我这个时候空间不够了,于是我让virtio_balloon驱动虚拟的占用了1个G的内存,那么这个时候KVM中就用掉了1.5G的内存,实际上只用了0.5G,但实际上这个1G内存我是虚拟占用的,我可以给其它KVM用。)
在QEMU monitor中,通过下面的命令来看内存使用大小:
info balloon:查看客户机的内存占用量
balloon num:设置客户机内存占用量为XXX MB
例子:

[root@RHEL65 kvm_demo]# qemu-system-x86_64 rhel6u5.img -smp 2 -m 1024 -net nic -net tap,script=/root/kvm_demo/qemu-ifup-NAT-2,downscript=no -vnc 192.168.19.105:1 -enable-kvm -balloon virtio

2.virtio_net
需要QEMU和客户机中驱动的支持。
virtio类型的网卡性能几乎等同于物理网卡。

例子:
这里的网卡使用了virtio:

[root@RHEL65 kvm_demo]# qemu-system-x86_64 rhel6u5.img -smp 2 -m 1024 -net nic,model=virtio,macaddr=00:16:3e:22:22:22 -net tap,script=/root/kvm_demo/qemu-ifup-NAT-2,downscript=no -vnc 192.168.19.105:1 -enable-kvm 

这里的tap设备使用了virtio(不一定快):

[root@RHEL65 kvm_demo]# qemu-system-x86_64 rhel6u5.img -smp 2 -m 1024 -net nic,model=virtio,macaddr=00:16:3e:22:22:22 -net tap,vnet_hdr=on,vhost=on,script=/root/kvm_demo/qemu-ifup-NAT-2,downscript=no -vnc 192.168.19.105:1 -enable-kvm

如果使用了virtio类型的网络设备后性能依旧不理想,检查bridge中物理网卡的GSO/TSO设置是否关闭。如果是打开的则把它关闭(ethtool -K eth0 gso off;ethtool -K eth0 tso off):

[root@RHEL65 ~]# ethtool -k eth0
Features for eth0:
rx-checksumming: on
tx-checksumming: on
scatter-gather: on
tcp-segmentation-offload: on #TSO
udp-fragmentation-offload: off
generic-segmentation-offload: on #GSO
generic-receive-offload: off
large-receive-offload: off
rx-vlan-offload: on
tx-vlan-offload: on
ntuple-filters: off
receive-hashing: off

3.virtio_blk
对IO设备的虚拟。

例子(通过-drive):
[root@RHEL65 kvm_demo]# qemu-system-x86_64 -drive file=rhel6u5.img,if=virtio -smp 2 -m 1024 -net nic,model=virtio,macaddr=00:16:3e:22:22:22 -net tap,vnet_hdr=on,vhost=on,script=/root/kvm_demo/qemu-ifup-NAT-2,downscript=no -vnc 192.168.19.105:1 -enable-kvm -balloon virtio
客户机器中的设备是/dev/vda,不是/dev/hda或/dev/sda。

4.KVM_CLOCK
默认应该就会用这个,在客户机中可以通过dmesg | grep -i clock查看是否有kvm-clock/TSC这类信息来判断。

16.VT-d
前面介绍了QEMU/KVM中使用设备的几种类型,主要有:纯软件模拟的QEMU设备和virtio的设备。前者效率较低,后者要装驱动。因此这里介绍的VT-d则是让KVM直接使用硬件设备。Intel叫做Virtualization Technology for Directed I/O,而AMD则是AMD-Vi。

原理是KVM将虚拟机中的PCI、PCI-E设备附加到客户机中。这样就可以直接使用网卡、磁盘控制器、USB控制器、VGA显示卡等功能了(但是同样的,这个设备就被虚拟机独占了)。但缺点是如果一个主机上有很多的客户机,无法保证能为每个客户都都分配一个独立的设备。

通过dmesg | grep DMAR -i或dmesg | grep IOMMU -i查看客户机是否编译了相关模块。

具体的分配方法是通过-device参数。

17.SR-IOV技术
为了解决VT-d技术的设备独占性问题而出现的。

18.热插拔
在QEMU monitor中通过device_add/device_del实现。

CPU也可以热插拔,但目前还不被支持。也是同样的在QEMU monitor中操作。

19.动态迁移
KVM即支持六线的静态迁移,也支持在线的动态迁移。
静态迁移:在QEMU中执行savevm XXX,然后关闭或暂停虚机,把镜像文件复制到另外一个物理机中,启动,然后在使用loadvm XXX来还原CPU、内存、设备状态。这里的镜像需要是qcow2、qed等。像raw这种则不支持快照功能。

动态迁移:一种是类似于vMotion的。测试的时候可以用NFS作为共享存储来测试。还有一种可以复制磁盘。

20.QEMU Monitor
一般通过Ctrl+Alt+2切换。对于SDL,如果添加了-alt-grab或-ctrl-grab,那么需要是ctrl+alt_shift+2来切换。
如果没有图形化界面,那么通过-monitor XXX来决定如何显示monitor,可以是vc(就是默认的那个,需要图形的),/dev/XXX,null,stdio

常用命令
help:帮助信息查看,一般是:help migrate、help device_add这样用
info:查看系统状态,主要有:info version,info kvm,info name,info status,info uuid,info cpus,info registers,info tlb,info mem,info numa,info mtree,info balloon,info pci,info qtree,info block,info chardev,info network,info usb,info usbhost,info snapshot,info migrate,info roms,info vnc,info history
commit:提交修改到磁盘
cont或c:从stop返回到继续工作
stop:暂停
change:修改某个配置,如change vnc XXX
savevm,loadvm,delvm:快照相关
sendkey:发送特定的键,如sendkey ctrl-alt-f1
system_powerdown:关闭电源
system_reset:重启
system_wakeup:从暂停中换醒

21.libvirt
之前的笔记都是通过qemu-system-x86_64来配置和启动客户机的。而libvirt则可以很方便的管理KVM。
virsh/virt-install/virt-manager/openstack/opennebula/eucalyptus底层都是调用libvirt。

libvirt是为了更加方便的管理KVM而设计的应用程序接口、守护进程和管理工具。支持KVM/QEMU/Xen/VMWare/VirtualBox等。

libvirt对于不同的Hypervisor是通过一种基于驱动的程序架构来实现的。比如对Xen有Xen的驱动,对KVM有KVM的驱动。其屏蔽了各个Hypervisor的细节,对上层展现一个统一的窗口。

查看是否安装:

[root@RHEL65 ~]# netstat -na | grep 192.168^C
[root@RHEL65 ~]# which  libvirtd
/usr/sbin/libvirtd
[root@RHEL65 ~]# rpm -q libvirt
libvirt-0.10.2-29.el6.x86_64
[root@RHEL65 ~]# libvirtd --version
libvirtd (libvirt) 0.10.2

基本概念:
节点:就是物理机
域:就是虚拟机

配置文件所在目录(qemu下是qemu驱动的配置文件):

[root@RHEL65 ~]# cd /etc/libvirt/
[root@RHEL65 libvirt]# pwd
/etc/libvirt
[root@RHEL65 libvirt]# ls
libvirt.conf  libvirtd.conf  lxc.conf  nwfilter  qemu  qemu.conf  storage

重要配置文件说明:
libvirt.conf:配置alias,用于远程控制的时候不要写那很长的连接字符串
libvirtd.conf :libvirtd守护进程的配置文件,比如设置TCP监听端口啥的
qemu.conf :对QEMU驱动的配置文件,如内存大页、认证方式等
qemu目录:对qemu虚拟机的配置。network是指的创建一个域的时候使用的默认的网络配置

libvirtd:
如果要让某个节点(物理机)可以被管理,就需要运行libvirtd。其它管理工具通过API与libvirtd通信,并控制虚拟机的行为。
可以用service命令控制,这里有一个reload选项,意思是补充其服务但是重新加载配置。也可以直接通过libvirtd这个命令启动。
libvirtd根据客户机的XML文件来发现客户机。如果没有XML文件则发现不了(这也就是为什么直接用qemu-system-X86_64运行的虚机不能通过virt-manager管理的原因)

libvirt对客户机(也就是域)的管理都是通过XML文件来的。比如网络配置、磁盘配置等。XML文件一般是通过命令或图形化界面自动生成的,比如我有一个虚拟机的域配置文件,那么启动的时候这个配置文件就会的转换成具体的KVM启动的参数。

libvirt的API通过URI来连接到本地或远程的Hypervisor。比如通过virsh工具进行连接(qemu表示driver的类型,ssh表示连接的方法,system表示管理最高权限):

virsh -c qemu:///system #连接本地,并且是最高权限
virsh -c qemu+ssh://root@192.189.1.1/system #连接远程,并且是最高权限

22.dump xml

[root@COMPUTE01 Desktop]# virsh dumpxml RHEL-6.5-img
<domain type='kvm' id='1'>
  <name>RHEL-6.5-img</name>
  <uuid>fdae0103-a5e4-79a9-0326-ed3ed9e15a44</uuid>
  <memory unit='KiB'>1048576</memory>
  <currentMemory unit='KiB'>1048576</currentMemory>
  <vcpu placement='static'>1</vcpu>
  <os>
    <type arch='x86_64' machine='rhel6.5.0'>hvm</type>
    <boot dev='cdrom'/>
    <boot dev='hd'/>
  </os>
  <features>
    <acpi/>
    <apic/>
    <pae/>
  </features>
  <clock offset='utc'/>
  <on_poweroff>destroy</on_poweroff>
  <on_reboot>destroy</on_reboot>
  <on_crash>destroy</on_crash>
  <devices>
    <emulator>/usr/libexec/qemu-kvm</emulator>
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2' cache='none'/>
      <source file='/root/Desktop/RHEL-6.5-img.qcow2'/>
      <target dev='vda' bus='virtio'/>
      <alias name='virtio-disk0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
    </disk>
    <disk type='file' device='cdrom'>
      <driver name='qemu' type='raw'/>
      <source file='/root/Desktop/rhel-server-6.5-x86_64-dvd.iso'/>
      <target dev='hdc' bus='ide' tray='open'/>
      <readonly/>
      <alias name='ide0-1-0'/>
      <address type='drive' controller='0' bus='1' target='0' unit='0'/>
    </disk>
    <controller type='usb' index='0'>
      <alias name='usb0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
    </controller>
    <controller type='ide' index='0'>
      <alias name='ide0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
    </controller>
    <interface type='network'>
      <mac address='52:54:00:4a:62:dc'/>
      <source network='default'/>
      <target dev='vnet0'/>
      <model type='virtio'/>
      <alias name='net0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
    </interface>
    <serial type='pty'>
      <source path='/dev/pts/1'/>
      <target port='0'/>
      <alias name='serial0'/>
    </serial>
    <console type='pty' tty='/dev/pts/1'>
      <source path='/dev/pts/1'/>
      <target type='serial' port='0'/>
      <alias name='serial0'/>
    </console>
    <input type='tablet' bus='usb'>
      <alias name='input0'/>
    </input>
    <input type='mouse' bus='ps2'/>
    <graphics type='vnc' port='5900' autoport='yes' listen='0.0.0.0'>
      <listen type='address' address='0.0.0.0'/>
    </graphics>
    <video>
      <model type='cirrus' vram='9216' heads='1'/>
      <alias name='video0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
    </video>
    <memballoon model='virtio'>
      <alias name='balloon0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
    </memballoon>
  </devices>
  <seclabel type='none'/>
</domain>

99.kvm其它命令
-monitor stdio:直接进入QEMU monitor,如:

[root@RHEL65 kvm_demo]# qemu-system-x86_64 rhel6u5.img -smp 2 -m 1024 -net nic -net tap,script=/root/kvm_demo/qemu-ifup-NAT-2,downscript=no -vnc 192.168.19.105:1 -enable-kvm -monitor stdio
QEMU 1.2.50 monitor - type 'help' for more information
(qemu) 
(qemu) help

-usb -usbdevice tablet 或 -device piix3-usb-uhci -device usb-tablet:
解决鼠标偏移问题

libvirtd删除虚机:

[root@COMPUTE02 qemu]# virsh destroy KVMTEST

退出:进入qemu monitor后输入quit。

virsh destroy XXX:停止一个domain(断电式的),这个时候virsh list就看不到啦,需要virsh list –all才能看到
virsh shutdown XXX:停止一个domain
virsh start XXX:启动一个domain
virsh define XXX.xml:从xml定义一个domain,但不启动
virsh undefine XXX:删除XXX这个domain的定义
virsh console KVMTEST:连接到KVMTEST的console上
virsh domdisplay KVMTEST:查看链接参数
virsh do mxml -from-native qemu-argv demo.args:将qemu的参数转成xml
virsh vncdisplay KVMTEST:查看vnc的端口和ip

保存当前的状态,之后通过start命令直接恢复到当前状态:

[root@COMPUTE01 ~]# virsh managedsave KVMTEST --bypass-cache --running --verbose
Managedsave: [100 %]
Domain KVMTEST state saved by libvirt
[root@COMPUTE01 ~]# virsh start KVMTEST
Domain KVMTEST started

virt-viewer KVMTEST:打开KVMTEST的vnc
virsh edit KVMTEST:直接编辑某个domain的xml

新的笔记:
1.查看CPU是否支持kvm(svm是AMD的,vmx是intel的)

[root@COMPUTE01 ~]# grep -E 'svm |vmx' /proc/cpuinfo

2.查看kvm模块是否加载(kvm_amd是AMD的,kvm_intel是intel的)

[root@COMPUTE01 ~]# lsmod | grep kvm
kvm_intel              54285  0 
kvm                   333172  1 kvm_intel

3.为windows安装virtio驱动

[root@COMPUTE02 ~]# yum install virtio-win

这个命令会下载下来一个virtio-win.iso,默认在/usr/share/virtio-win/下面。然后在windows上面从这个iso中把驱动装上。
这个在virtualization guide中有很详细的介绍。

4.virsh*
virsh-install:安装的时候用。装好后会的生成一个xml文件(其实就是比qemu-kvm多了一个生成xml的功能,这个xml供libvirtd使用。所以如果考虑生成xml这个功能的话,这个命令完全可以看成就是qemu-kvm)
virsh:对虚机做操作的时候用。可以直接指定虚机的名字,然后就能启动了(因为信息都在xml中)。另外对虚机的一些操作(比如增加volume)都可以通过这个来弄,如:virsh attach-disk –type cdrom –mode readonly centos-6.4 “” hdc,virsh start centos-6.4
virsh-manager:图形化界面。如果是新建虚机,那么类似于virsh-install,会生成xml文件。如果是启动虚机啥的,就类似于virsh

virsh可以交互。不会的话用help命令看帮助,这个也可以看子命令的帮助,比如help vol-list

virsh如果使用了–config参数,那么相关的修改只会的写入xml文件中,不会立刻让运行着的虚机生效,虚机需要重启了才生效
如果没有使用–config参数,那么会让现在的虚机生效,但虚机destroy后在start是不会生效的(因为xml文件没有变)
如果要都生效的话,运行两次。

5.xml和状态文件、运行时文件所在目录
默认的xml存放目录:

[root@COMPUTE02 qemu]# pwd
/etc/libvirt/qemu

可以直接用vi编辑,不过推荐使用virsh(或图形化的virsh-manager)修改

状态文件(image、snapshot啥的都在这里):

[root@COMPUTE02 qemu]# cd /var/lib/libvirt/
[root@COMPUTE02 libvirt]# ls
boot  dnsmasq  filesystems  images  lxc  network  qemu

运行时文件:

[root@COMPUTE02 libvirt]# pwd
/var/run/libvirt
[root@COMPUTE02 libvirt]# ls
libvirt-sock  libvirt-sock-ro  network  qemu
[root@COMPUTE02 libvirt]# cd qemu/
[root@COMPUTE02 qemu]# ls
KVM01.pid  KVM01.xml

日志文件:

[root@COMPUTE02 libvirt]# ls
libvirtd.log  lxc  qemu  uml
[root@COMPUTE02 libvirt]# pwd
/var/log/libvirt

6.virbr0
安装了qemu后,自动生成这个bridge和一个叫做virbr0-nic的网卡。这个就是qemu的NAT网络,通过ps可以看到具体的NAT的程序:

[root@COMPUTE02 qemu]# ifconfig vir*
virbr0    Link encap:Ethernet  HWaddr 52:54:00:C7:DC:9B  
          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)

[root@COMPUTE02 qemu]# ps -elf | grep dns
5 S nobody    2340     1  0  80   0 -  3222 poll_s May05 ?        00:00:00 /usr/sbin/dnsmasq --strict-order --local=// --domain-needed --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
0 S root      3774  2816  0  80   0 - 25812 pipe_w 00:51 pts/0    00:00:00 grep dns

如果新建立的虚机的nic是用的NAT,那么都会的被加入到这个网络中,然后获得一个192.168.122.X的IP。

7.storage pool
就是存放volume的地方,可以是目录,NFS,iSCSI,LVM,MFS等。可以通过virsh或virsh-manager配置。配置好后之后建立volume的时候就能选择建立在哪个pool中:

virsh # pool-list
Name                 State      Autostart 
-----------------------------------------
default              active     yes       

virsh # pool-info default
Name:           default
UUID:           b135432c-1c29-a159-f5ce-6ac224792303
State:          running
Persistent:     yes
Autostart:      yes
Capacity:       36.25 GiB
Allocation:     9.81 GiB
Available:      26.44 GiB

默认的storage pool是在/var/lib/libvirt/images下

8.volume
就是虚机的盘。查看方法如下:

virsh # vol-list default
Name                 Path                                    
-----------------------------------------
KVM01.img            /var/lib/libvirt/images/KVM01.img       

virsh # vol-list default --details
Name       Path                               Type   Capacity  Allocation
-------------------------------------------------------------------------
KVM01.img  /var/lib/libvirt/images/KVM01.img  file  20.00 GiB       0.00 

9.libvirtd对xml的读取顺序
当启动libvirtd的时候,会的去/etc/libvirt/qemu中读取.xml结尾的文件,然后放入内存中。比如我现在有一个KVM01.xml的文件,定义了一台KVM01的虚机,那么virsh list –all就可以看到这台虚机。
但要注意的是,这种行为(也就是直接去/etc/libvirt/qemu中读取生成虚机列表的行为)只有在libvirtd启动的时候会进行。当libvirtd启动后,这个目录中的东西就没用了,因为信息都已经读取到内存中了。这个时候把这个目录中的东西删了都是不会影响什么的(不过如果重启libvirtd,那么再次启动的时候就发现不了这些虚机了)

在运行的时候,可以通过define和create增加新的domain,这两个都能在内存中写入相关的虚机的信息。但是前者可以在libvirtd重启后依然保留信息,后者不行。原因可以看下面的第10点。

10.virsh的create和define命令
两个都是在libvirtd运行的是增加xml到其内存中。
区别:
10.1 create的话会的直接启动xml定义的虚机,但libvirtd重启后会丢失这个虚机的信息。而define则只是定义,并且相关的xml文件会保存在libvirtd的对应目录,libvirtd重启后依然有相关的信息(比如virsh define /tmp/aaa.xml,则会把这个aaa.xml复制一份到/etc/libvirt/qemu中,名字是aaa.xml虚机的名字加上.xml后缀,但不启动它。如果是virsh create的话,不会的把/tmp/aaa.xml复制到/etc/libvirt/qemu中,但是会的从aaa.xml启动这个虚机,也就是说这种启动是一次性的,下次libvirtd重启后就没有了)。
10.2 define命令可以更新某个虚机的xml定义

简单的说,define就是把xml复制一份到/etc/libvirt/qemu(但区别在于,由于上面所讲到的,/etc/libvirt/qemu只有在libvirtd重启的时候才会被读取,所以直接复制的话新的xml中的虚机信息不会存在在libvirtd的内存中,但通过define则可以加入到libvirtd的内存链表结构中,这样通过virsh list –all就能看到了)。而create则是从xml生成qemu-kvm XXX的命令,然后启动一台虚机,但libvirtd重启后这些信息就消失了(因为没有把xml复制到/etc/libvirt/qemu中)

所以如果要持久化自己定义的xml的虚机的话,需要建立一个xml文件,然后用define命令定义(当然啦,直接把xml文件复制到/etc/libvirt/qemu也是可以的,只有重启下libvirtd,那么效果是一样的)

另外,aaa.xml文件里的uuid如果删除的话,define的时候会自动生成。这个比较实用。

define的反操作是undefine,其会从libvirtd的内存中删除相关的domain,并移除对应的xml文件:

[root@COMPUTE01 qemu]# virsh undefine KVMTEST02

11.domain和node
kvm中,把物理机host称之为node。把虚拟机称之为domain

12.从img中生成xml文件
可以在virt-manager中new domain的时候,选择from existing image。然后就能有对应的xml文件了。不过一般还是建议从已有的系统上复制过来一个,然后name改掉,uuid那一行删了,然后把必要的地方做个修改,然后define到libvirtd中。

13.qemu-img
创建特定格式的image:

[root@COMPUTE01 ~]# qemu-img create -f qcow2 rhel6u5.img 5G

检测image的完整性(只针对qcow2和vdi格式):

[root@COMPUTE01 ~]# qemu-img check -f qcow2 rhel6u5.img 
No errors were found on the image.
Image end offset: 262144

backing file:
在创建image的时候可以指定-o参数,然后加这个backing file为源image(base image)。然后生成的image(称之为overlay)只会保存和这个backing_file不同的数据,而不会对backing_file做修改(copy-on-write):

[root@COMPUTE01 ~]#  qemu-img create -f qcow2 -o backing_file=rhel6u5.img rhel6u5_02.img 5G
Formatting 'rhel6u5_02.img', fmt=qcow2 size=5368709120 backing_file='rhel6u5.img' encryption=off cluster_size=65536 

之后对rhel6u5_02.img的修改只会的保存在rhel6u5_02.img中,而不会写入到rhel6u5.img。除非使用commit命令,才会把相关的修改写入rhel6u5_02.img中。
另外可以通过rebase命令重新指定某个image的backing file,原理就是把overlay的那个盘中的老的base image和新的base image的差异信息写入overlay的盘,使得其就好像是从新的base image中生成的一样。
对于base image,不建议去使用,原因是为了防止不一致的情况出现。
那么backing file到底有什么用呢?(可以看下http://www.linux-kvm.com/content/how-you-can-use-qemukvm-base-images-be-more-productive-part-1)

commit修改到base盘:
讲增量的盘的差异数据写入base盘,相关的信息见backing file:

[root@COMPUTE01 ~]# qemu-img commit -f qcow2 rhel6u5_02.img 
Image committed.

关于commit的信息是很复杂的,具体的可以看“http://itxx.sinaapp.com/blog/content/130”这篇文章。比如我overlay可以下推到base file,base file也可以合并到overlay,难点有几个,比如涉及到image的snapshot chain。

查看磁盘信息:
一般用于看磁盘的真正大小(注意,由于snapshot的存在,一个image实际占用的大小可能远大于分配的大小。比如我建立的image的大小是100M,但我做了很多的快照,可能实际占用的空间会占用500M,但实际可用空间还是100M):

[root@COMPUTE01 ~]# qemu-img info -f qcow2 rhel6u5.img 
image: rhel6u5.img
file format: qcow2
virtual size: 5.0G (5368709120 bytes)
disk size: 136K
cluster_size: 65536

convert格式:

qemu-img convert -f raw -O qcow2 centos1.img centos1qcow2.img

resize:
注意,如果要调小,需要在vm中把文件系统先调小。如果调大,调完后需要在文件系统中调大文件系统。raw都支持,qcow2需要RHEL 6.1后支持:

[root@COMPUTE01 ~]# qemu-img resize rhel6u5.img 6G
Image resized.
[root@COMPUTE01 ~]# qemu-img resize rhel6u5.img - 1G
Image resized.
[root@COMPUTE01 ~]# qemu-img resize rhel6u5.img + 1G
Image resized.

snapshot:
-l:查看snapshot的个数
-c:创建一个snapshot
-a:恢复到某个snapshot
-d:删除一个snapshot

[root@COMPUTE01 ~]# qemu-img snapshot -l rhel6u5.img 
[root@COMPUTE01 ~]# qemu-img snapshot -c snapshot01 rhel6u5.img 
[root@COMPUTE01 ~]# qemu-img snapshot -l rhel6u5.img 
Snapshot list:
ID        TAG                 VM SIZE                DATE       VM CLOCK
1         snapshot01                0 2014-05-06 19:44:09   00:00:00.000
[root@COMPUTE01 ~]# qemu-img snapshot -a snapshot01 rhel6u5.img 
[root@COMPUTE01 ~]# qemu-img snapshot -d snapshot01 rhel6u5.img 
[root@COMPUTE01 ~]# qemu-img snapshot -l rhel6u5.img 

快照详细信息(参考http://itxx.sinaapp.com/blog/content/130):
快照有三种(一种是内存、磁盘状态啥的都保存在qcow2的盘中,另一种是做个backing file,然后新的东西都写在overlay的image中。还有一种是只把内存中的信息导出来,写入一个文件):
1.内置快照(Internal Snapshots):单个qcow2镜像文件存储了包括数据以及快照的状态信息,内置快照又能分成两种:
内置磁盘快照(Internal disk snapshot):快照点的磁盘状态,数据和快照保存在单个qcow2文件中,虚拟机运行状态和关闭状态都可以创建。qemu使用 ‘qemu-img’ 命令创建关机状态的磁盘快照,qemu 使用 ‘savevm’ 命令创建运行状态的磁盘快照.
内置系统还原点(Internal system checkpoint):内存状态,设备状态和磁盘状态,可以为运行中的虚拟机创建,所有信息都存储在同一个qcow2文件中,只有在运行状态才能创建内置系统还原点。qemu使用’savevm’ 命令来创建这种快照
2.外置快照(External Snapshots):当一个快照被创建时,创建时当前的状态保存在当前使用的磁盘文件中,即成为一个backing file。这之后的操作会的在一个overlay的盘上做操作。这个也可以细分成两种:
外置磁盘快照(External disk snapshot):磁盘的快照被保存在一个文件中,创建时间点以后的数据被记录到一个新的qcow2文件中。可以在运行和关闭状态创建。qemu 使用 ‘transaction’ 命令来为运行状态创建这种快照(好像也不怎么能用现在)。qemu 使用’qemu-img’ 命令为关闭状态创建这种快照(截止目前功能还在开发中).
外置系统还原点(External system checkpoint):虚拟机的磁盘状态将被保存到一个文件中,内存和设备的状态将被保存到另外一个新的文件中(这个功能也还在开发中).
3.VM状态(VM state):保存运行状态虚拟机的内存设备状态信息至文件,可以通过此文件恢复到保存时的状态,有点类似系统的休眠.(注意创建VM状态保存的时候VM磁盘必须是未发生写入改动的)。qemu使用 ‘migrate’ (to file)命令来完成VM状态转储.

14.virsh对虚机状态的修改测试
启动一个domain:

virsh start domain

suspend一个domain(只是IO和CPU暂停了,但内存还是在消耗的,可以发现kvm的进程也是存在的):

[root@COMPUTE01 ~]# virsh suspend KVMTEST
Domain KVMTEST suspended
[root@COMPUTE01 ~]# virsh list
 Id    Name                           State
----------------------------------------------------
 4     KVMTEST                        paused
[root@COMPUTE01 ~]# ps -elf | grep kvm
1 S root      2695     2  0  80   0 -     0 worker 19:16 ?        00:00:00 [kvm-irqfd-clean]
6 S qemu     32855     1  3  80   0 - 302615 poll_s 21:18 ?       00:02:47 /usr/libexec/qemu-kvm -name KVMTEST -S -M rhel6.5.0 -enable-kvm -m 800 -realtime mlock=off -smp 1,sockets=1,cores=1,threads=1 -uuid f803fee0-adcc-1738-5c19-ec9a3c582337 -nodefconfig -nodefaults -chardev socket,id=charmonitor,path=/var/lib/libvirt/qemu/KVMTEST.monitor,server,nowait -mon chardev=charmonitor,id=monitor,mode=control -rtc base=utc -no-shutdown -device piix3-usb-uhci,id=usb,bus=pci.0,addr=0x1.0x2 -drive file=/var/lib/libvirt/images/KVMTEST.img,if=none,id=drive-virtio-disk0,format=raw,cache=none -device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x5,drive=drive-virtio-disk0,id=virtio-disk0,bootindex=1 -drive 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:50:56:6d,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=0x6
1 S root     32862     2  0  80   0 -     0 worker 21:18 ?        00:00:00 [kvm-pit-wq]
0 S root     33362 32668  0  80   0 - 25814 pipe_w 22:32 pts/2    00:00:00 grep kvm

resume一个domain:
virsh resume KVMTEST

save一个domain(保存内存,cpu信息到一个文件,同时停止虚拟机,速度受到内存大小的影响。这个就是qemu的第三种快照VM状态快照):

[root@COMPUTE01 ~]# virsh save KVMTEST /tmp/kvmtest.state --bypass-cache 
Domain KVMTEST saved to /tmp/kvmtest.state

restore一个domain(从save产生的那个文件中恢复):

[root@COMPUTE01 ~]# virsh restore /tmp/kvmtest.state 
Domain restored from /tmp/kvmtest.state

shutdown,就是正常的关机(就相当于root用户在虚拟机里执行shutdown -h now):

[root@COMPUTE01 ~]# virsh shutdown KVMTEST

reboot,就是正常的重启虚机:

[root@COMPUTE01 ~]# virsh reboot KVMTEST

reset,就是类似于按电源的重置按钮,会丢失数据:

[root@COMPUTE01 ~]# virsh reset KVMTEST

15.virsh获取虚拟机信息

[root@COMPUTE01 ~]# virsh dominfo KVMTEST
Id:             -
Name:           KVMTEST
UUID:           f803fee0-adcc-1738-5c19-ec9a3c582337
OS Type:        hvm
State:          shut off
CPU(s):         1
Max memory:     819200 KiB
Used memory:    819200 KiB
Persistent:     yes
Autostart:      disable
Managed save:   no
Security model: none
Security DOI:   0

16.virsh的快照实践
注意,–live参数在RHEL企业版不支持,只有RHEL的虚拟化virtualization版本支持。如果没有这个参数,那么做快照的期间虚拟机是处于暂停状态的,做完后自动恢复正常状态。

snapshot-create:从XML创建快照
snapshot-create-as:从参数创建快照
snapshot-current:获取当前的(最新的)快照
snapshot-delete:删除一个快照
snapshot-dumpxml:dump快照的xml
snapshot-list:列出domain的快照
snapshot-revert:跳转到某个快照

测试(这个命令就类似qemu monitor中的savevm,snapshot会保存在qcow2的image中。最后的state表明虚拟机的状态,running表明是在线的时候做的):

[root@COMPUTE01 images]# virsh snapshot-create-as KVMTEST snap01
Domain snapshot snap01 created
[root@COMPUTE01 images]# virsh snapshot-list KVMTEST
 Name                 Creation Time             State
------------------------------------------------------------
 snap01               2014-05-06 23:46:57 -0700 running
 

恢复snapshot(这个命令就类似于qemu中的loadvm,就是先把vm启动起来,然后在qemu monitor中调用loadvm snap02):

[root@COMPUTE01 images]# virsh snapshot-revert KVMTEST snap02 --force

只生成xml文件而不进行快照操作:

[root@COMPUTE01 images]# virsh snapshot-create-as KVMTEST snap02 --print-xml

查看某一快照的xml信息(通过这个可以看到某一个快照的硬件配置等情况):

[root@COMPUTE01 images]# virsh snapshot-dumpxml KVMTEST snap02

默认如果运行snapshot-create-as的时候不加–disk-only或–memspec参数,那么就是使用内置快照(存放在qcow2中,需要pause一段时间)。如果不希望暂停,需要使用外置快照。

17.qemu中的快照实践
进去qemu monitor,运行savevm即可(或者可以加一个快照的名字,如savevm aaa)。之后可以通过qemu-img info XXX.img或qemu-img snapshot -l XXX.img查看快照信息。
如果要还原,可以在qemu monitor中list snapshots查看下具体的snapshot,然后通过loadvm aaa还原某个快照。

18.在线迁移、在线快照的理解
先看快照。从上面的一些信息我可以猜测,qcow2中可以保存vm的内存信息,但只是简单的内存信息。因此在做在线的快照的时候,必须要有一段时间处于暂停的状态,否则这段时间内内存、磁盘的改变是没办法记录到qcow2中的(因为前面讲了,这个qcow2只能保存最简单的内存信息,增量的内存信息不能记录)
那么有没有办法做在线的不会进入暂停状态的快照呢?可以的,通过backing file。做快照的瞬间,生成一个backing file,然后此时的内存进入copy-on-write状态,如果overlay的磁盘改变了,那么只会的反映到overlay的磁盘上。如果overlay的内存改变了,那么会在新的地方生成内存,而老的内存不变。与此同时,老的内存会在后台复制到base image中。等到内存复制完成后,内存中老的内存就可以消失了。此时我们的base image中就存在了做快照的时间点的磁盘和vm内存状态。也就是说,对于真正的在线快照,需要一个backing file,也就是所谓的external checkpoint。

然后看在线迁移。对于共享存储的比较简单,就是复制内存状态同时记录增量内存,然后在10ms内把增量内存复制到目的主机。我们来看下非共享存储的。内存方面还是和共享存储一样,来看磁盘,在做快照的瞬间,会生成一个backing file,然后base image会复制到目的主机,等到相关的准备工作都就绪后(原先的内存和base的image都复制完成),就会进入一个瞬间,这个瞬间会把overlay image和增量内存传到目的主机中。最后可能overlay image和base image会做个合并。

19.libvirt中的网络
默认有一个virbr0的网桥,是一个NAT的网络(如果看这个网络不顺眼,可以virsh net-undefine default删除它:

[root@COMPUTE01 ~]# brctl show
bridge name bridge id       STP enabled interfaces
pan0        8000.000000000000   no      
virbr0      8000.5254002733df   yes     virbr0-nic
                            vnet0

这个网络是哪里来的呢?在/etc/libvirt/qemu/networks中有相关的xml配置文件,libvirtd启动的时候会读取这个目录下autostart中的xml文件,根据这些xml文件建立对应的网络。
如果要删除默认的网络的话,可以从autostart中把对应的xml的链接删除,然后重启相关的服务(直接重启主机比较方便。)

virsh对网络的操作:
virsh net-autostart networkXXX [–disable]:设置当vm启动的时候,相关的网络是否要启动
virsh net-create fileXXX:从xml文件生成一个网络,类似于virsh create XXX,但是不会一直保存
virsh net-define fileXXX:定义一个网络但不启动
virsh net-undefine fileXXX:删除一个网络的定义
virsh net-destroy networkXXX:立刻停止某个网络
virsh net-start networkXXX:启动一个网络
virsh net-dumpxml networkXXX [–inactive]:查看某个网络的xml配置
virsh net-edit networkXXX:编辑某个网络的xml
virsh net-info networkXXX:查看某个网络的信息
virsh net-list [–inactive | –all ] [–persistent] [<--transient>] [–autostart] [<--no -autostart>]:查看网络信息

默认的kvm使用了virtual Realtek8139这个虚拟网卡,这个性能比较低。但RHEL使用virtio NIC。可以通过xml文件(virsh edit XXX)查看使用的是不是virtio NIC:

<interface type='network'>
  <mac address='52:54:00:50:56:6d'/>
  <source network='default'/>
  <model type='virtio'/>
  <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</interface>    

如果type不是virtio,可以改成virtio,然后重启虚机。

1 Response

  1. Tianqi Ma 2017年7月21日 / 下午9:42

    Wo ,你写的好详细,学习了,帮助很大,谢谢!!!

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*