在Host之间迁移Guest是一个复杂的问题,有许多可能的解决方案,每个解决方案都各有优劣。为了实现「Hypervisor集成」和「管理员部署」的最大灵活性,libvirt实现了多种迁移选项。

数据的传输方式

迁移期间使用的数据传输有两种选择:可以是Hypervisor的「原始传输」;或者通过libvirtd连接进行「隧道传输」。

原始传输(由Hypervisor提供)

「原始传输」不一定支持加密,取决于所讨论的Hypervisor,但通常会通过最小化所涉及的数据副本的数量来实现最低的计算成本。「原始传输」还需要管理员在部署Host时进行额外的“Hypervisor特定”的网络配置步骤。对于某些Hypervisor,可能需要在防火墙上打开大量端口,以允许多个并发迁移操作。

隧道传输(由libvirt提供)

「隧道传输」能够进行强加密,因为它们能够利用libvirt的RPC协议中内置的功能。然而,「隧道传输」的缺点是,当数据在libvirtd和Hypervisor之间移动时,源主机和目标主机上都会涉及额外的数据副本。对于RAM非常大的Guest来说,这可能是一个更重要的问题,这会很快损坏内存页面。在部署方面,「隧道传输」不需要对libvirtd进行额外的网络配置,满足「远程访问」即可,并且只需要在防火墙上打开单个端口以支持多个并发迁移操作。

通讯的控制流

迁移虚拟机需要对「所涉及的两个主机」以及「调用迁移的程序」进行紧密协调,这可能有三台主机:源主机、目的主机、第三个主机。

管理的直接迁移(通过client完成)

通过「管理直接迁移」,「libvirt客户端进程」可控制迁移的各个阶段。「客户端」必须能够同时与「源主机」和「目标主机」上的libvirtd守护程序进行连接和身份验证。两个libvirtd守护进程不需要相互通信。如果「客户端」在迁移过程中因为崩溃(或以其他方式)失去与libvirtd的连接,则将尝试中止迁移,并重新启动「源主机」上的Guest的CPU。可能存在无法安全完成此操作的情况,在这种情况下,Guest将暂停在一个或两个主机上。

管理的对等迁移(通过libvirtd完成)

通过「对等迁移」,「libvirt客户端进程」只与「源主机」上的「libvirtd守护进程」通信。「源libvirtd守护程序」通过直接连接「目标主机libvirtd」来控制整个迁移过程。如果「客户端程序」因崩溃(或以其他方式)失去与libvirtd的连接,迁移过程将继续不间断直到完成。

请注意,「源libvirtd」使用自己的凭据(通常是root)连接到「目标libvirtd」,而不是「客户端」用于连接「源libvirtd」的凭据;如果这些不同,通常会遇到「客户端」可以直接连接到「目标主机」,但是「源主机」无法建立对等迁移的连接的情况。

非管理直接迁移(由Hypervisor完成)

使用「非管理直接迁移」,「libvirt客户端」或「libvirtd守护程序」都不会控制迁移过程。相反,控制权被下方给Hypervisor的管理服务(如果有的话)。「libvirt客户端」仅通过「hypervisor的管理层」启动迁移。如果libvirt客户端或libvirtd崩溃,迁移过程将继续不间断直到完成。

有关于数据安全

由于迁移数据流包括Guest OS RAM的完整副本,因此监听迁移数据流可能会危害Guest信息。如果Host多个网络接口,或者交换机支持「VLAN标签」,则从「迁移/管理流量」中分离出「Guest网络流量」是非常可取的。

在某些情况下,即使是「单独的数据迁移网络」也可能无法提供足够的安全性。在这种情况下,可以对「迁移数据流」进行加密。如果Hypervisor本身不提供加密,则应使用「libvirt的隧道传输」。

关于「迁移URI」的说明

「启动Guest虚拟机迁移」需要「客户端应用」指定最多三个URI,具体取决于所「选择的控制流」和「使用的API」。



第一个URI是与「源主机的libvirt」连接的URI,即Guest当前正在运行的那台机器。



第二个URI是与「目标主机的libvirt」连接的URI,即Guest将被移动到的主机(在「对等迁移」中,这是从「源」的角度来看,而不是「客户端」)。



第三个URI是「特定于Hypervisor」的URI,用于控制Guest虚拟机的迁移方式。



对于任何「管理直接迁移」的迁移流,第一个和第二个URI是必需的,而第三个URI是可选的。使用「非管理直接迁移」模式,第一个和第三个URI是强制的,第二个URI不使用。

通常,「管理应用程序」只需关心第一个和第二个URI,它们都是常见的libvirt连接URI格式。然后,Libvirt将通过查找目标主机配置的主机名自动确定「Hypervisor特定的URI」。在某些情况下,「管理应用程序」可能希望直接控制第三个URI:



配置的主机名不正确,或DNS已损坏。如果Host的主机名无法解析为IP地址,则libvirt将生成不正确的URI。在这种情况下,「管理应用程序」应使用「IP地址」或「正确的主机名」明确指定「Hypervisor特定的URI」。



主机有多个网络接口。如果主机具有多个网络接口,则出于安全性或性能原因,可能需要通过特定接口发送迁移数据流。在这种情况下,「管理应用程序」应使用「与要使用的网络关联的IP地址」来指定「Hypervisor特定的URI」。



防火墙限制可用的端口。当libvirt生成迁移URI时,它将使用管理程序特定规则选择端口号。某些虚拟机管理程序只需要在防火墙中打开一个端口,而其他虚拟机管理程序则需要一系列端口号。在后一种情况下,管理应用程序可能希望选择超出默认范围的特定端口号,以符合本地防火墙策略。



配置文件处理

在libvirt中,已知有两种类新的虚拟机:



* 临时状态:只在运行时存在,配置文件没有存储在磁盘上; * 持久状态:配置文件存储在磁盘上,即使Guest没有运行;



默认情况下,迁移动作不会修改「目的主机」和「源主机」上的配置文件。应该由管理员(或应用程序)负责管理配置文件的分发。注意/etc/libvirt/目录不应该在主机间共享。

下面是几种典型的场景:



在libvirt外部,集中的配置文件,位于共享存储中。「群集感知管理应用程序」可以将所有「主Guest配置文件」维护在群集文件系统中。尝试启动Guest虚拟机时,将从「群集文件系统」读取配置,并用于部署「持久Guest虚拟机」。对于迁移,需要将配置复制到「目标主机」,并在「原始主机」上删除。



在libvirt外部,集中的配置文件,位于数据库中。「数据中心管理应用程序」可能根本不存储配置文件。相反,它可以在引导Guest虚拟机时动态生成libvirt XML。它通常使用临时Guest虚拟机,因此在迁移期间不必考虑配置文件。



在libvirt中的分布式配置。每个Guest虚拟机的配置文件将复制到Guest虚拟机可以运行的每个Host。迁移后,现有配置只需要更新任何更改。



在libvirt内部的临时配置管理。每位Guest都与特定Host绑定,很少迁移。需要迁移时,配置将从一个Host移动到另一个Host上。



如上所述,默认情况下,libvirt不会在迁移期间修改配置文件。命令virsh有两个标志来控制这种行为:



* ''--undefine-source'':在成功迁移后,删除「源主机」上的配置文件。 * ''--persist'':在成功迁移后,在「目标主机」上创建配置文件。



在手册中有一张表,总结各种情况下,配置文件的结果:「Configuration file handling」

常见的迁移场景

# Native migration, client to one libvirtd server

在API级别,需要使用virDomainMigrateToURI,未设置VIR_MIGRATE_PEER2PEER标志,参数uri为「Hypervisor特定的URI」格式。

不使用/不要求「目标主机」存在「libvirtd实例」。当Hypervisor有自己的「原始管理守护程序」来处理在「目标主机」中传入的迁移尝试时,通常会使用此方法。



#!/bin/sh

# syntax: virsh migrate GUESTNAME HV-URI

# eg using same libvirt URI for all connections
virsh migrate --direct web1 xenmigr://desthost/

# CLIENT -> SRC LIVBIRTD -> SRC HYPERVISOR -> DEST HYPERVISOR



支持驱动:Xen

# Native migration, client to two libvirtd servers

在API级别,需要使用virDomainMigrate,不设置VIR_MIGRATE_PEER2PEER标志。

「目标主机上的libvirtd服务」将根据「主要主机名」自动确定「用于迁移的原始Hypervisor URI」。



#!/bin/sh

# syntax: virsh migrate GUESTNAME DEST-LIBVIRT-URI [HV-URI]

# eg using default network interface
virsh migrate web1 qemu+ssh://desthost/system
virsh migrate web1 xen+tls://desthost/system

# eg using secondary network interface
# 要强制通过备用网络接口进行迁移,必须提供「Hypervisor特定的URI」
virsh migrate web1 qemu://desthost/system tcp://10.0.0.1/
virsh migrate web1 xen+tcp://desthost/system  xenmigr:10.0.0.1/



支持驱动:Xen, QEMU, VMware, VirtualBox

Native migration, client to and peer2peer between, two libvirtd servers

virDomainMigrate,设置了VIR_MIGRATE_PEER2PEER标志,参数uri使用的libvirt URI格式。

「目标libvirtd服务」将根据「主要主机名」自动确定「用于迁移的原始Hypervisor URI」。可选的uri参数控制「源libvirtd」如何连接到「目标libvirtd」,以防它使用「客户端用于连接到目标主机的相同地址」无法访问,或者需要不同的「加密/身份验证」方案。使用此方法无法为「原始迁移」强制使用备用网络接口。

无法从virsh调用此模式

被QEMU驱动支持

# Native migration, peer2peer between two libvirtd servers

virDomainMigrateToURI,设置了VIR_MIGRATE_PEER2PEER标志,参数uri使用libvirt URI格式。「目标libvirtd服务」将根据「主要主机名」自动确定用于迁移的「原始Hypervisor URI」。使用此方法无法为「原始迁移」强制使用备用网络接口。必须使用源libvirtd凭据(在连接到「源主机」时不一定与客户端的凭据相同)才能访问目标URI。



#!/bin/sh

# syntax: virsh migrate GUESTNAME DEST-LIBVIRT-URI [ALT-DEST-LIBVIRT-URI]

# eg using same libvirt URI for all connections
virsh migrate --p2p web1 qemu+ssh://desthost/system

# eg using different libvirt URI auth scheme for peer2peer connections
virsh migrate --p2p web1 qemu+ssh://desthost/system qemu+tls:/desthost/system

# eg using different libvirt URI hostname for peer2peer connections

virsh migrate --p2p web1 qemu+ssh://desthost/system qemu+ssh://10.0.0.1/system



被QEMU驱动支持

Tunnelled migration, client and peer2peer between two libvirtd servers

virDomainMigrate,设置了VIR_MIGRATE_PEER2PEER和VIR_MIGRATE_TUNNELLED标志,参数uri使用的libvirt URI格式。「目标libvirtd服务」将根据「主要主机名」自动确定用于迁移的「原始Hyperviros URI」。可选的uri参数控制「源libvirtd」如何连接到「目标libvirtd」,以防它使用「客户端用于连接到目标主机的相同地址」无法访问,或者需要不同的「加密/身份验证」方案。不使用「原始Hypervisor URI」格式。

无法从virsh调用此模式

由QEMU驱动程序支持

# Tunnelled migration, peer2peer between two libvirtd servers

virDomainMigrateToURI,设置了VIR_MIGRATE_PEER2PEER和VIR_MIGRATE_TUNNELLED标志,参数uri使用libvirt URI格式。「目标libvirtd服务」将根据「主要主机名」自动确定用于迁移的「原始Hypervisor URI」。可选的uri参数控制「源libvirtd」如何连接到「目标libvirtd」,以防它使用「客户端用于连接到目标主机的相同地址」无法访问,或者需要不同的「加密/身份验证」方案。不使用「原始Hypervisor URI」格式。必须使用「源libvirtd凭据」(在连接到「源」时不一定与「客户端」的凭据相同)才能访问目标URI。



#!/bin/sh

# syntax: virsh migrate GUESTNAME DEST-LIBVIRT-URI [ALT-DEST-LIBVIRT-URI]

# eg using same libvirt URI for all connections
virsh migrate --p2p --tunnelled web1 qemu+ssh://desthost/system

# eg using different libvirt URI auth scheme for peer2peer connections
virsh migrate --p2p --tunnelled web1 qemu+ssh://desthost/system qemu+tls:/desthost/system

# eg using different libvirt URI hostname for peer2peer connections
virsh migrate --p2p --tunnelled web1 qemu+ssh://desthost/system qemu+ssh://10.0.0.1/system