静态迁移是指在虚拟机关闭或暂停的状况下,将源宿主机上虚拟机的磁盘文件和配置文件拷贝到目标宿主机上。这种方式须要显式的中止虚拟机运行,对服务可用性要求高的需求不合适。
***
动态迁移无需拷贝虚拟机配置文件和磁盘文件,可是须要迁移的主机之间有相同的目录结构放置虚拟机磁盘文件,能够经过多种方式实现,本例采用基于共享存储动态迁移,经过NFS来实现。ubuntu
源宿主机:Ubuntu17.10 Server版操做系统,4.10.0-38-generic内核。下文中以“Node1”表示,主机名为Service,IP地址为192.168.200.132,NFS挂载目录/opt。
目标宿主机:Ubuntu17.10 Server版操做系统,4.10.0-38-generic内核。下文中以“Node2”表示,主机名为Service1,IP地址为192.168.200.131,NFS挂载目录/opt。
基于QEMU的动态迁移虚拟机镜像文件为ubuntu16server.img。
基于libvirt的静态迁移测试虚拟机:demo1,IP为192.168.200.132,虚拟镜像文件为ubuntu16.img。
基于libvirt的动态迁移测试虚拟机:demo2,IP为192.168.200.131,虚拟镜像文件为ubuntu16.img。
NFS服务器:Ubuntu17.10 Server版,4.10.0-38-generic内核。IP地址为192.168.200.130,服务目录为/opt/share。vim
KVM虚拟机动态迁移无需拷贝虚拟机配置文件和磁盘文件,可是须要迁移的主机之间有相同的目录结构放置虚拟机磁盘文件(本例为“/opt/share”目录),这里的动态迁移是基于共享存储动态迁移,经过NFS来实现,须要QEMU 0.12.2以上版本支持。可使用如下命令查看安装的QEMU的版本号。api
qemu-img --help|grep version安全
首先在NFS服务器上,下载安装NFS,kernel-server至关于server端,common是client端,使用命令如下命令进行安装NFS:服务器
sudo apt-get install nfs-kernel-server nfs-common -y网络
配置NFS服务器,将NFS服务器上的“/opt/share”目录设为服务目录。首先使用如下命令建立目录,而后修改建立的目录权限,同时若是不放心是否权限修改了,能够查看下文件夹的权限,修改后为“drwxr-xr-x”app
sudo mkdir /opt/share,
sudo chmod 777 /opt/share
sudo ll /optdom接下来使用vim修改“/etc/exports”:文件添加共享目录,在该文件最后添加如下内容便可。/opt/share:表示要设置的共享目录,_*_:表示容许全部的网段访问,也可使用具体的IP。rw:表示挂载此目录的客户端对该共享目录具备读写权限。sync:表示资料同步写入内存和硬盘。no_root_squash:表示root用户具备对根目录的彻底管理访问权限。no_subtree_check:表示不检查父目录的权限。修改完毕后保存退出。ssh
/opt/share *(rw,sync,no_subtree_check,no_root_squash)socket
_“/etc/exports”_文件修改后,使用命令而后进行刷新。最后启动NFS服务,命令以下:
sudo exportfs –r
sudo /etc/init.d/rpcbind restart
sudo /etc/init.d/nfs-kernel-server restartNFS服务启动后,在Node1上使用如下命令查看远程主机的共享目录,能够看到如下斜体内容
sudo showmount -e 192.168.200.130
root@Service:~# sudo showmount -e 192.168.200.130
Export list for 192.168.200.130:
/opt/share *分别在Node1和Node2上分别挂载NFS服务器的共享文件夹到本地“/opt”目录中,而后将Node1上的的虚拟磁盘文件ubuntu16server.img(前面实验中制做的ubuntu的镜像文件)拷贝到挂载NFS服务器共享目录的文件夹“/opt”中(我制做好的镜像文件在/root文件夹中),以后能够看到ubuntu16server.img镜像文件。在节点2上执行一样的操做,但在Node2中不用执行拷贝这一命令。
sudo mount -t nfs 192.168.200.130:/opt/share /opt -o rw
sudo cp /root/ubuntu16server.img /opt挂载拷贝完成后两节点都有相同的虚拟机磁盘文件存储目录
在Node1上使用以下命令启动虚拟机,ubuntu16server.img为前面实验制做的镜像文件,-monitor stdio表示能够进入QEMU监控器,以便接下来执行迁移命令。
qemu-system-x86_64 -hda ubuntu16server.img -m 1024 -smp 1 -vnc :0 -monitor stdio
(qemu)- 打开VNC界面,链接节点1上的QEMU虚拟机,登录以后并执行“top”命令,能够看到界面一直在发生改变。
在Node2上使用如下命令启动一个虚拟机,该虚拟机并无真实启动,只是用于等待接收动态迁移过来的内存内容,使用VNC链接后显示界面状态为黑屏,或者是有一行提示。这里须要注意:在Node2上,NFS挂载目录必须与源主机上保持一致;启动客户机命令也需一致,可是须要增长-incoming 选项。“-incoming tcp:0:6666” 这个参数表示在6666 端口创建一个tcp socket 链接用于接收来自于源宿主机的动态迁移的内容,其中“0”表示容许来自任何主机的链接,“-incoming”表示使QEMU进程进入到迁移监听(migration-listen)模式,而不是真正以命令行中的镜像文件运行客户机。另外,这里是以NFS服务器上的镜像文件做为虚拟机磁盘来启动虚拟机,若是有多个用户同时使用NFS服务器上的镜像文件,请将镜像文件在本地进行派生,使用派生后的镜像文件启动虚拟机,具体方式读者可自行查阅相关资料
qemu-system-x86_64 -hda /opt/ubuntu16server.img -m 1024 -smp 1 -vnc :0 -incoming tcp:0:6666
在Node1源宿主机的qemu monitor 命令行中输入如下命令迁移虚拟机,进入动态迁移的流程,其中“192.168.200.131”是目标宿主机IP,TCP协议和6666端口与目标宿主机上命令行的-incoming 参数保持一致
(qemu) migrate tcp:192.168.200.131:6666 //(qemu)为启动镜像时出现的qemu monitor
- 在Node1上执行"migrate"命令从开始到执行完成,大约十秒钟(视网络而定),在执行完成后迁移成功。迁移后在Node2上,也就是目标宿主机上,以前处于迁移监听状态的虚拟机开始运行,在该虚拟机中能够查看到,原来在Node1上运行的虚拟机上执行的top命令在迁移后仍在继续在Node2上执行。
至此基于QEMU的虚拟机动态迁移完成
- 静态迁移也叫作常规迁移、离线迁移(Offline Migration)。是在虚拟机关机或暂停的状况下,拷贝虚拟机磁盘文件与配置文件从源宿主机到目标宿主机中,实现的从一台物理机到另外一台物理机的迁移。由于虚拟机的文件系统创建在虚拟机镜像文件上面,因此在虚拟机关机的状况下,只须要简单的迁移虚拟机镜像和相应的配置文件到另一台物理主机上便可。若是须要保存虚拟机迁移以前的状态,那么应该在迁移以前将虚拟机暂停,而后拷贝状态至目标宿主机,最后在目标宿主机重建虚拟机状态,恢复执行。这种方式的迁移过程须要显式的中止虚拟机的运行。从用户角度看,有明确的一段停机时间,虚拟机上的服务不可用。这种迁移方式简单易行,适用于对服务可用性要求不严格的场合。
为网络添加br0网桥
sudo brctl addbr br0
sudo brctl addif br0 ens33
sudo brctl stp br0 on
sudo ifconfig ens33 0
sudo dhclient br0在Node1上进行操做,首先肯定demo虚拟机状态为“shut off”,若是不是能够执行“destroy
” 进行关闭sudo virsh list --all
准备迁移demo虚拟机,查看demo虚拟机的磁盘文件
virsh domblklist
导出虚拟机配置文件demo.xml、ubuntu16.img,将其发送到Node2中与Node1中文件对应的文件夹(demo.xml文件在文章结尾会给出代码)
sudo scp /root/demo.xml /root/ubuntu16.img 192.168.200.131:/root
- 以后开始在目标宿主机Node2上进行虚拟机的配置和启动。
使用virsh的子命令define定义并注册demo虚拟机
sudo virsh define /root/demo.xml
启动迁移后的demo虚拟机,经过VNC查看,VNC端口查看
sudo virsh vncdisplay
而后经过VNC查看是否能够登录和其余操做
- 此处我说明下,这种迁移虽然为基于Libvirt的动态迁移,可是其迁移的只是虚拟机的状态而不是虚拟机的状态和文件,这一点我再次特别说明。
将Node1上的“ubuntu16.img”发送到Node2对应的文件夹,此时的demo状态为“shut off”,发送后启动demo虚拟机
sudo scp /root/ubuntu16.img 192.168.200.131:/root
查看Node1上虚拟机状态,demo虚拟机保证处于“runing”(若是demo处于“shut off”,将其启动运行“sudo virsh start demo”)
sudo virsh list --all
- 查看Node2上虚拟机状态,确保无虚拟机运行,命令如上
- 经过VNC链接登录,并执行"top"命令
在Node1上执行“virsh migrate”迁移命令,虚拟机demo在迁移出去的过程当中,状态有从“running”到“shut off”的一个改变。--verbose 指迁移demo虚拟机,192.168.200.131为节点2的IP地址,使用tcp协议链接,--unsafe参数表示跳过安全检测, /system为以root身份进行状态迁移,qemu+ssh表示为经过ssh通道链接到远程节点的system实例,具备最大权限来管理远程节点上的虚拟机资源
sudo virsh migrate --live --verbose demo qemu+ssh://192.168.200.131/system tcp://192.168.200.131 --unsafe
在Node2上,查看虚拟机demo虚拟机状态为“runing”
sudo virsh list --all
- 在迁移过程当中,能够经过另一台客户机一直ping虚拟机demo,查看demo迁移过程当中的可链接性。实际上迁移过程除了偶尔有几个包的中断,基本上没有太大影响
此时虽然demo虚拟机已经在Node2上启动了,可是Node2上尚未demo虚拟机的配置文件。这时须要建立配置文件并定义该虚拟机,能够经过迁移过来的虚拟机内存状态建立虚拟机配置文件,而后经过xml配置文件定义虚拟机。
sudo virsh dumpxml demo > /etc/libvirt/qemu/demo1.xml //之因此命名为demo1.xml是由于,在libvirt静态迁移过程当中已经有个demo.xml文件,虽然不在同一个文件夹,为了不搞混。
sudo virsh define /etc/libvirt/qemu/demo1.xml经过VNC链接查看,VNC端口号查询。
sudo virsh vncdisplay demo
- 在经过VNC链接上后发现迁移前的“top”命令依然在执行
至此,demo虚拟机迁移完成。
<!-- WARNING: THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE OVERWRITTEN AND LOST. Changes to this xml configuration should be made using: virsh edit demo or other application using the libvirt API. --> <domain type='kvm'> <name>demo</name> <uuid>782ca9b9-8403-4fcd-979e-e4f038aaeb15</uuid> <memory unit='KiB'>1048576</memory> <currentMemory unit='KiB'>1048576</currentMemory> <vcpu placement='static'>1</vcpu> <os> <type arch='x86_64' machine='pc-i440fx-trusty'>hvm</type> <boot dev='cdrom'/> <boot dev='hd'/> </os> <features> <acpi/> <apic/> <pae/> </features> <clock offset='localtime'/> <on_poweroff>destroy</on_poweroff> <on_reboot>restart</on_reboot> <on_crash>destroy</on_crash> <devices> <emulator>/usr/bin/kvm</emulator> <disk type='file' device='disk'> <driver name='qemu' type='qcow2'/> <source file='/home/ubuntu16.img'/> <target dev='hda' bus='ide'/> <address type='drive' controller='0' bus='0' target='0' unit='0'/> </disk> <controller type='usb' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> </controller> <controller type='pci' index='0' model='pci-root'/> <controller type='ide' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> </controller> <interface type='bridge'> <mac address='52:54:00:c0:a2:8a'/> <source bridge='br0'/> <model type='rtl8139'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> </interface> <input type='tablet' bus='usb'/> <input type='mouse' bus='ps2'/> <input type='keyboard' bus='ps2'/> <graphics type='vnc' port='-1' autoport='yes' listen='0.0.0.0' keymap='en-us'/> <video> <model type='cirrus' vram='9216' heads='1'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> </video> <memballoon model='virtio'> <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> </memballoon> </devices> </domain>