KVM虚拟机在物理主机之间迁移的实现

迁移(migration)包括系统整体的迁移和某个工作负载的迁移。
系统的整体迁移,是将系统上的所有软件(也包括操作系统)完全复制到另外一台物理硬件机器上。而工作负载的迁移是将系统撒谎嗯某个工作负载起那一另外一台物理机器上运行。
服务器系统迁移的作用在于简化了系统的维护管理,提高了系统的负载均衡,增强了负载的容错性,并优化了系统的电源管理。
虚拟化环境中的静态迁移也可以分为两种,第一种是关闭客户机后,将其硬盘镜像复制到另外一台宿主即机中然后恢复启动起来。这种迁移不能够保证客户机中运行的工作负载。另外一种是两台宿主机共享存储系统,只需要暂停客户机,复制其内存镜像到另外一台宿主机中恢复启动,这种迁移可以保证客户机迁移前的内存状态和系统运行的工作负载
动态迁移:是指在保证客户机上应用服务正常运行的同时,让客户机在不同的宿主机之间进行迁移,其逻辑步骤和前面的静态迁移几乎一致,有硬盘存储和内存都复制的动态迁移,也有仅内存镜像迁移的。不同的是,为了保证迁移过程中客户机服务的可用性,迁移过程仅有非常短暂的停机时间。动态迁移允许系统管理员将客户机在不同的宿主机上进行迁移,同时不会断开访问客户机中服务的客户端或者应用程序的连接。
一个成功的动态迁移,需要保证客户机的内存、硬盘存存储、网络连接在迁移到目的主机后依然保持不变,而且迁移过程的服务暂停时间较短。
动态迁移的应用场景:负载均衡、解除硬件依赖、节约能源、实现客户机地理位置的远程迁移。
动态迁移的条件:源宿主机和目的宿主机共享存储系统,只需要通过网络发送客户机的vCPU执行状态,内存中的内容,虚拟设备的状态到目的主机上。否则就需要将客户机的磁盘存储发送到目的主机上。
虚拟机迁移技术为服务器虚拟化提供了便捷的方法。而目前流行的虚拟化工具如 VMware,Xen,HyperV,KVM 都提供了各自的迁移组件。尽管商业的虚拟软件功能比较强大,但是开源虚拟机如 Linux 内核虚拟机 KVM 和 XEN 发展迅速,迁移技术日趋完善。虚拟机迁移有三种方式,分别是P2V、V2V 和 V2P,不同的方式又存在许多不同的解决方案。
在虚拟化环境中的迁移又分为动态迁移和静态迁移。(也有人称作冷迁移,热迁移,或者离线迁移,在线迁移)。静态迁移和动态迁移的最大的区别在于静态迁移有明显的一段时间客户机的服务不能用,而动态迁移则没有明显的服务暂停。
静态迁移是指在虚拟机关闭或暂停的情况下,将源宿主机上虚拟机的磁盘文件和配置文件拷贝到目标宿主机上。这种方式需要显式的停止虚拟机运行,对服务可用性要求高的需求不合适。
动态迁移无需拷贝虚拟机配置文件和磁盘文件,但是需要迁移的主机之间有相同的目录结构放置虚拟机磁盘文件,可以通过多种方式实现,本例采用基于共享存储动态迁移,通过NFS来实现。
静态迁移也叫做常规迁移、离线迁移(Offline Migration)。是在虚拟机关机或暂停的情况下,拷贝虚拟机磁盘文件与配置文件到目标虚拟主机中,实现的从一台物理机到另一台物理机的迁移。因为虚拟机的文件系统建立在虚拟机镜像文件上面,所以在虚拟机关机的情况下,只需要简单的迁移虚拟机镜像和相应的配置文件到另外一台物理主机上即可。如果需要保存虚拟机迁移之前的状态,那么应该在迁移之前将虚拟机暂停,然后拷贝状态至目的主机,最后在目的主机重建虚拟机状态,恢复执行。这种方式的迁移过程需要显式的停止虚拟机的运行。从用户角度看,有明确的一段停机时间,虚拟机上的服务不可用。这种迁移方式简单易行,适用于对服务可用性要求不严格的场合。
KVM虚拟机迁移原理:虚拟机迁移过程中数据的传输(磁盘镜像和内存数据),通常有两种常用的数据传输方式:
基于hypervisor的传输机制,即通过host之间连接来进行数据传输
基于libvirtd的传输机制,即两个libvirtd进程之间的数据传输

基于hypervisor的数据传输
这种传输方式具有最低的overload,因为传输的是裸数据,不支持数据的加密。另外,因为依赖于hypervisor的网络,所以需要对hypervisor networks进行一些特定的配置,比如打开某些端口。
hypervisor_based_datatransfer

基于libvirtd的数据传输
这种传输方式支持加密,是通过libvirt内建的RPC协议来进行数据的传输的,但是缺点是除了传输裸数据外,还需要传输一些额外的数据,这对镜像尺寸很大的虚拟机来说是个大问题。优点是由于不依赖与hypervisor network,所以不需要hypervisor对network做过多的配置,仅仅打开某个指定的port即可。
libvirtd_datatransfer

虚拟机迁移过程中的控制流
带有管理端的直接迁移:这种迁移方式是由一个管理客户端发起,管理客户端完全控制整个迁移流程,所以它必须能够且有权限访问源主机和目的主机上libvirtd的权限,因为外加一个管理客户端,所以不需要源libvirtd和目的libvirtd之间进行直接的交流,只需要按照管理客户端的指示来办事就好了。
control_stream_datatransfer

带有管理端的点对点的迁移
这种迁移方式下,管理客户端至于源libvirtd交互,然后源libvirtd完全控制整个迁移过程。优点是,即使管理客户端挂掉了,迁移还是能正常完成的。
p2p_migration

静态迁移过程较为简单,故作者开发了脚本程序来实现虚拟机静态迁移。
源码:Github
虚拟机静态迁移效果图:

上面的图为执行虚拟机转移端的脚本执行图。
下面的图为迁移到另外一台虚拟机的效果图。

KVM虚拟机动态迁移无需拷贝虚拟机配置文件和磁盘文件,但是需要迁移的主机之间有相同的目录结构放置虚拟机磁盘文件(本例为“/home/kvm”目录),这里的动态迁移是基于共享存储动态迁移,通过NFS来实现,需要qemu-kvm-0.12.2以上版本支持。
在NFS服务器上,下载安装NFS,kernel-server相当于server端,common是client端,使用命令

# sudo apt-get install nfs-kernel-server nfs-common rpcbind

安装NFS,在客户端机上使用命令

# sudo apt-get install nfs-common

安装NFS客户端。
若要实现虚拟机动态迁移,则至少需要三台虚拟机。以10.211.55.7为IP地址的虚拟机为NFS服务器。以10.211.55.6为IP地址的虚拟机为源虚拟机,以10.211.55.3为IP地址的虚拟机为目标虚拟机。
在NFS服务器上,可随时使用如下命令查看服务器共享目录:

# showmount -e 10.211.55.7

在NFS服务器上配置共享目录,首先使用命令

# sudo mkdir /root/share

创建该目录,然后使用命令

# sudo chmod -R 777 /root/share

修改该目录权限,接下来使用vim修改“/etc/exports”文件添加共享目录,在该文件中添加“/root/share (rw,sync)”即可。(rw,sync)是命令参数,表示包括读写权限。
“/etc/exports”文件修改后,使用命令

# sudo exportfs –r

刷新。然后启动NFS服务,命令如下:

# sudo /etc/init.d/rpcbindr restart
# sudo /etc/init.d/nfs-kernel-server restart

效果如图所示:

在客户机上可使用如下命令挂载并查看NFS目录:

# mount -t nfs 10.211.55.7://root/share /root/share-disk -o rw
# df && ll /root/share-disk/

如下图所示,可以看到另外一台虚拟机已经成功挂载nfs磁盘镜像:

接下来,在源宿主机上建立WinXP的XML描述文件,可使用多种方法。
在成功配置WinXP后,可以看到可以ping通内网外网。

从图中的Terminal可以看到,使用

# virsh list —all

命令可以看到虚拟机winxp正在运行,准备执行虚拟机迁移操作:

接下来执行虚拟机动态迁移。为了保证动态迁移的准确性,我们选择在NFS服务器上ping WinXP虚拟机以查看是否断开:

# ping 10.211.55.8

在源主机上输入以下命令以执行虚拟机迁移操作:

# virsh migrate winxp —live qemu+ssh://10.211.55.3/system tcp://10.211.55.3/system —unsafe

在命令执行前即开始ping操作,一直到结束停止ping操作。NFS服务器ping虚拟机效果图:

上图为迁移后的源宿主机。
下图为目标机。可以看到虚拟机启动后的状态仍为迁移前的状态未动。

至此,虚拟机的动态迁移操作完成。

在虚拟机迁移过程中,遇到过提示错误:
无法在 ‘br0’获取接口MTU:没有那个设备
解决方案:源主机与宿主机同时建立br0网桥,可使用如下命令:

#root@master:~# brctl addbr br0        #增加一个虚拟网桥br0
#root@master:~# brctl addif br0 eth0    #在br0中添加一个接口eth0
#root@master:~# brctl stp br0 on        #打开STP协议,否则可能造成环路
#root@master:~# ifconfig eth0 0        #将eth0的IP设置为0
#root@master:~# dhclient br0          #设置动态给br0配置ip、route等
#root@master:~# route                #显示路由表信息
#root@master:~# brctl show    #显示网桥信息

若需要持久化br0网桥,可直接写入/etc/network/interfaces文件解决。

虚拟机静态迁移工具源码:

#!/bin/bash
read -p "Please Input Domain Name to Migrate: " -s domainName
cd ~/
echo Preparing VMs basic files, please wait...
mkdir $domainName > /dev/null
virsh dumpxml $domainName >  ~/$domainName/$domainName.xml

qcow2=$(virsh dumpxml $domainName | grep qcow2 | grep file | sed "s/'/#/g" | sed "s/'/#/g" | sed -r 's/.*#(.*)#.*/\1/')

if [ $qcow2=='' ]
then
     img=$(virsh dumpxml $domainName | grep img | grep file | sed "s/'/#/g" | sed "s/'/#/g" | sed -r 's/.*#(.*)#.*/\1/')
fi

if [ $qcow2=='' ]
then
     raw=$(virsh dumpxml $domainName | grep raw | grep file | sed "s/'/#/g" | sed "s/'/#/g" | sed -r 's/.*#(.*)#.*/\1/')
fi

if [ -n "$qcow2" ]
then
        cp $qcow2 ~/$domainName/
elif [ -n "$img" ]
then
        cp $img ~/$domainName/
elif [ -n "$raw" ]
then
        cp $raw ~/$domainName/
else
        echo $domainName is not exist. Please check again.
fi
echo VM Files Preparing finished.
read -p "Please Input The Remote Host IP: " -s remotehostIP
read -p "Please Input Remote Host Username: " -s remotehostUsername
echo If needed, you need to input remoteHost user password.
dircreate="mkdir ~\/"$domainName
softinstall="sudo apt-get install libvirt-bin kvm qemu virtinst virt-manager virt-viewer"
vmregister="virsh define ~\/"$domainName"\/"$domainName".xml"
ssh -t -p 22 $remotehostUsername@$remotehostIP $dircreate
scp ~/$domainName/* $remotehostUsername@$remotehostIP:~/$domainName
echo Register Remote Host VMs...
ssh -t -p 22 $remotehostUsername@$remotehostIP $softinstall
ssh -t -p 22 $remotehostUsername@$remotehostIP $vmregister
echo VMs Static Migration Finished.