迁移(Migration)就是把一个虚拟机从一台物理主机搬到另一台物理主机,动态(Live)就是在迁移过程中虚拟机正常工作不影响用户的使用。对系统管理员来说,动态迁移是个非常有用的工具,当计划对一个物理主机进行更新或者升级(update/upgrade)的时候,管理员不需要关闭这个物理主机上的虚拟机,只是在更新或者升级前把虚拟机动态迁移到另外一个物理主机,等更新或者升级工作完成后,在迁移回来。从用户的角度来看,好像这个过程没有发生。虚拟机虽然迁来迁去,但丝毫不会影响用户的使用。
本文尝试回答与 Live migration 相关的几个问题:Live migration 是什么?为什么要做 Live migration?如何做 Live migration?如果你读完本文,基本了解了这三个问题的答案, 这篇文章的主要目的也就达到了。由于本文介绍的是 OpenStack 平台上动态迁移的实现,所以读者必须对 OpenStack 有一定的了解。
虚拟机迁移简介
动态迁移包括两方面的意思,一是迁移(Migration),迁移就是把用户的虚拟机从一台物理主机移到另外一台物理主机。二是动态,动态的意思就是在迁移的过程中,(1):虚拟机还开着机;(2):虚拟机的网路也不受影响;(3):而且上面的运行的用户程序依旧运行。整个过程对用户来说是透明的,对用户可以正常使用迁移途中的虚拟机。
OpenStack 支持两种类型的虚拟机迁移:
- 冷迁移(Cold migration)- 冷迁移也叫静态迁移。在迁移过程中虚拟机必须关机,用户也不能访问虚拟机。因为要关机,所以他适用于用户对系统可用性要求不是很高的时候。
- 热迁移(Hot or live migration)- 热迁移也叫动态迁移。在迁移的过程中虚拟机仍旧工作,用户可以继续使用虚拟机。本文就介绍的就是这种类型的迁移。热迁移又分为下面二种类型:
- (1):虚拟机的数据存在共享磁盘上(Shared storage-based live migration),如图 1 所 示。
图 1
- (2):虚拟机的数据存在本地磁盘(block migration),如图 2 所示,需要对镜像文件和内存数据同时迁移。OpenStack 通过块迁移实现这这类迁移。
图 2
虚拟机迁移的作用
每个读者都可能会问这样一个问题,虚拟机用的好好的,为啥要迁移呀?也就是迁移的价值和目的在哪里。在数据中心的日常运维中,常常要处理下面几种场景和需求,了解了这些需求,这个问题也就有了答案。
- 需求 1:物理机器硬件系统的维护,故障修复和升级(upgrade),但运行在这台物理机器上的虚拟机不能关机,因为用户重要的服务跑在上面。
- 需求 2:物理机器软件系统升级,打补丁(patch),为了不影响上面跑的虚拟机,在升级和打补丁之前,需要把虚拟机迁移到别的物理机器上。
- 需求 3:一个物理机器上的负载太重,需要减少一些虚拟机来释放资源。
- 需求 4:在一个 cluster 里,有的物理机上的虚拟机太多,有的物理机上虚拟机太少,需要做一下资源平衡。
除了上面四个主要的需求,从服务的角度来看,Live migration 有下面两个好处:
- 好处 1:软件和硬件系统的维护升级,不会影响用户的关键服务,提高了服务的高可用性和 用户的满意度。
- 好处 2:系统管理员不用加班加点,在大半夜进行系统升级了,在正常的工作时间就可以完成这项工作,减少了公司的维护费用。
有这四个需求和两个好处,所以动态迁移值得一作。
动态迁移方法和实现
本章详细介绍在 OpenStack 里如何实现动态迁移。在第一节里,提到了有两种类型的动态迁移,本文只介绍图 2 所示的虚拟机的数据存在本地磁盘(block migration)的动态迁移。
动态迁移的条件
动态迁移是把虚拟机从一个物理主机迁移到另外一个物理主机,所以至少需要有两个物理主机作为计算节点。下面是一个最小的 OpenStack 配置。 三个物理主机,一个用来做 OpenStack 的控制节点,两个用来做计算节点。如图 3 所示。
图 3
控制节点接受并处理动态迁移的请求,管理员可以从 Horizon、命令行、API 发起动态迁移。 动态迁移就是把客户的 VM 从计算节点 1 迁移到计算节点 2,或者从计算节点 2 迁移到计算节点 1,如图 4 所示。
图 4
计算节点上的 Hypervisor 是 KVM,操作系统是 redhat6.5,OpenStack 是 Juno。计算节点 1 和 2 上的虚拟机分别存储在本地文件系统,如图 2 所示。
上面提到的 Hypervisor 和 KVM 相关概念,以及 OpenStack 各个模块的详细介绍,您可以阅读参考资料里文档,这里不在做介绍。
动态迁移的实现
本节分别从基本概念、传输协议和迁移的步骤三个方面介绍动态迁移是如何实现的。
基本概念
在了解动态迁移之前,必须了解镜像文件的格式 QCOW2。Qcow2 是 QEMU 目前推荐的镜像格式,它支持稀疏文件以节省存储空间,支持加密以提高镜像文件的安全性,支持基于 zlib 的压缩。Qcow2 镜像可以用来保存另一个镜像文件的变化,它并不去修改原始镜像文件,原始镜像文件也叫后端镜像(backing_file)。只记录与原始镜像文件的不同部分的镜像文件,这种镜像文件就叫做 copy-on-write 镜像,它虽然是一个单独的镜像文件,但它的大部分数据都来自原始镜像,只有基于原始镜像文件的增量部分才会被记录下来。本文提及的虚拟机都是 OpenStack 用 Qcow2 格式的镜像文件建立的,如图 5 所示,包含两部分。
- 后端镜像(libvirt base)
- 虚拟机单独的增量镜像文件(libvirt instance disks),copy-on-write 镜像
图 5
在物理机的磁盘上,当我们建了一个虚拟机后,就会生成如图 6 列的这些文件。其中_base 下面的文件,就是后端镜像(libvirt base),目录 6e783272-31b5-4fdc-8828-2b8892daab39 下面是虚拟机单独的增量镜像文件(libvirt instance disks),它只记录和 base 文件不同的内容。
图 6
用 qemu-img 查看虚拟机单独的增量镜像文件的信息,我们可以看到他的 backing file 是_base 目录下的镜像文件,如图 7 所示。
图 7
费了这么多篇幅介绍 QCOW2,您会奇怪,目的何在?其实上面介绍的后端镜像(libvirt Base),虚拟机单独的增量镜像文件(libvirt instance disks),它们就是要被迁移的数据。动态迁移的最终目标就是把它们完整地从源物理主机迁移到目标物理主机。除了他们两个之外,还有一个需要迁移的对象就是内存里运行的虚拟机的数据。
总结一下:虚拟机的迁移,其实就是数据的转移,因为计算节点之间没有共享存储,所以要转移的数据包括两部分:
- 静态数据:存储在本地的虚拟机的镜像文件,包括后端镜像(libvirt Base)和虚拟机单独的增量镜像文件(libvirt instance disks)。
- 动态数据:内存里虚拟机的运行时数据,内存里的数据是动态变化的数据,虚拟机里运行的负载的大小直接影响迁移的时间长短。
迁移通道和传输协议
OpenStack 调用底层的 libvirt 来完成动态迁移。虚拟机的迁移,其实就是数据的转移。libvirt 提供了隧道化的数据传输(libvirt tunnelled transport)方式来完成数据转移。如图 8 所示。
图 8
数据的转移就涉及数据的传输,数据的传输需要通过网络,本文介绍使用 TCP 网路协议完实现动态迁移。Libvirt 默认情况下不支持 TCP 协议,需要对 libvirt 的配置做修改,使 libvirt 能够支持 TCP 协议,后面的章节会详细的介绍如何配置。 在迁移的过程中,运行在目的物理主机(Dest Host)中的 libvirtd 进程要根据 address 和 port 创建一个 URI,URI 是目的物理主机用来接收数据和发回数据到源物理主机(Source Host)的 libvirtd 进程的,如图 9。
图 9
在目的物理主机和源物理主机,只要下面的命令能够执行,就说明能够传输数据了。
在 compute01 上执行:
[root@compute01]# virsh -c qemu+tcp://nova@compute02/system
在 compute02 上执行:
[root@compute01]# virsh -c qemu+tcp://nova@compute02/system
如下例所示在 compute01 上执行 virsh 命令,如果有图 10 所示的输出,就说明传输通道正常。
图 10
迁移的步骤
迁移的基本概念弄清楚了,下面我们继续介绍迁移的步骤。OpenStack 做动态迁移一个正常的流程主要包括四部分:迁移前的条件检查、迁移前的预处理、迁移、迁移后的处理。
迁移前的条件检查
动态迁移要成功执行,一些条件必须满足,所以在执行迁移前必须做一些条件检查。
- 权限检查,执行迁移的用户是否有足够的权限执行动态迁移。
- 参数检查,传递给 API 的参数是否足够和正确,如是否指定了 block-migrate 参数。
- 检查目标物理主机是否存在。
- 检查被迁移的虚拟机是否是 running 状态。
- 检查源和目的物理主机上的 nova-compute service 是否正常运行。
- 检查目的物理主机和源物理主机是否是同一台机器。
- 检查目的物理主机是否有足够的内存(memory)。
- 检查目的和源物理主机器 hypervisor 和 hypervisor 的版本是否相同。
迁移前的预处理
在真正执行迁移前,必须做一下热身,做一些准备工作。
- 在目的物理主机上获得和准备虚拟机挂载的块设备(volume)。
- 在目的物理主机上设置虚拟机的网络(networks)。
- 目的物理主机上设置虚拟机的防火墙(fireware)。
迁移
条件满足并且做完了预处理工作后,就可以执行动态迁移了。主要步骤如下:
- 调用 libvirt python 接口 migrateToURI,来把源主机迁移到目的主机。
- dom.migrateToURI(CONF.live_migration_uri % dest,logical_sum,None,CONF.live_migration_bandwidth)
- live_migration_uri:这个 URI 就是在 3.2.2 里介绍的 libvirtd 进程定义的。
- live_migration_bandwidth:这个参数定义了迁移过程中所使用的最大的带宽。
- 以一定的时间间隔(0.5)循环调用 wait_for_live_migration 方法,来检测虚拟机迁移 的状态,一直到虚拟机成功迁移为止。
迁移后的处理
当虚拟机迁移完成后,要做一些善后工作。
- 在源物理主机上 detach volume。
- 在源物理主机上释放 security group ingress rule。
- 在目的物理主机上更新数据库里虚拟机的状态。
- 在源物理主机上删除虚拟机。
上面四步正常完成后,虚拟机就成功的从源物理主机成功地迁移到了目的物理主机了。系统管理员就可以执行第二章所列的哪些管理任务了。
动态迁移的配置
本节列出了支持动态迁移的配置,必须确保所有物理主机上配置真确,动态迁移才能成功完成。
Libvirt
libvirt 默认情况下支持远程连接的 TLS 协议,不支持 TCP 协议,因此将 listen_tls=0 listen_tcp=1 使 libvirt 能够支持 TCP 协议。
- 修改/etc/sysconfig/libvirtd 文件。
LIBVIRTD_ARGS="--listen" - 在/etc/libvirt/libvirtd.conf 文件中做如下配置。
listen_tls=0 listen_tcp=1 auth_tcp="none" - 重启 libvirtd 服务
物理主机上 DNS
配置每个物理主机上的/etc/host,加入每个物理主机的 hostname 和 IP,如下例:
192.168.0.1 compute-1 compute-1.ibm.com 192.168.0.2 compute-2 compute-2.ibm.com
防火墙
配置/etc/sysconfig/iptables,打开 TCP 端口 16509。
-A INPUT -p tcp -m multiport --ports 16509 -m comment --comment "libvirt" -j ACCEPT
OpenStack Nova
在/etc/nova/nova.conf 文件里配置 live_migration 标记。live_migration_flag=VIR_MIGRATE_UNDEFINE_SOURCE,VIR_MIGRATE_PEER2PEER,VIR_MIGRATE_LIVE
动态迁移的实例
本节通过下面的例子来演示如何做动态迁移。这个例子的目标就是把虚拟机从 tor01kvm001ccz048 迁移到 tor01kvm002ccz048。如图 11 所示。
图 11
- 在 tor01kvm001ccz048 上建一个虚拟机 lm001,如图 12 所示。
点击查看代码清单
图 12
- 检查虚拟机 lm001 建在了 tor01kvm001ccz048 上,如图 13 所示。
图 13
- 执行动态迁移
#nova live-migration --block-migrate lm001 tor01kvm002ccz048
我们可以看到虚拟机的 Task State 变成了 migrating 状态,如图 14 所示。
图 14
- 检查迁移的结果
通过 nova show 命令,可以看到 lm001 已经成功迁移到了 tor01kvm002ccz048,如图 15 所示。
图 15
总结
从前面的介绍我们可以看出,即使没有共享存储,我们也可以对虚拟机实现无中断的动态迁移,不过所有的计算节点之间需要快的网路支持。另外还需要注意两点:
- 本文使用的是没有没有加密的 TCP/IP socket,所以在生产环境不推荐使用,除非是在一个安全可信的网路里执行动态迁移。
- 在迁移的过程中,虚拟机会有 downtime。详细的信息,可以阅读参考资料里的块迁移的性能报告。