Live disk migration with libvirt blockcopy

QEMU and libvirt projects has had a lot of block layer improvements in its last few releases (libvirt 1.2.6 & QEMU 2.1).
This post discusses a method to do live disk storage migration with libvirt’s blockcopy.
QEMU和libvirt项目在最近的几个版本(libvirt 1.2.6和QEMU 2.1)中有很多块层的改进。这篇文章讨论了一种使用libvirt的blockcopy进行实时磁盘存储迁移的方法。

一、Context on libvirt blockcopy
Simply put, blockcopy facilitates virtual machine live disk image copying (or mirroring) — primarily useful for different use cases of storage migration:
简单地说,blockcopy促进了虚拟机动态磁盘镜像的复制(或监控)——主要适用于存储迁移的不同用例
Live disk storage migration
热磁盘存储迁移
Live backup of a disk image and its associated backing chain
磁盘映像及其关联备份链的实时备份
Efficient non-shared storage migration (with a combination of virsh operations snapshort-create-as+blockcopy+blockcommit)
高效的非共享存储迁移(结合virsh操作snapshort-create-as+blockcopy+blockcommit)
As of IceHouse release, OpenStack Nova project also uses a variation of libvirt blockcopy, through its Python API virDomainBlockRebase, to create live snapshots, nova image-create.
(More details on this in an upcoming blog post).
在IceHouse发布时,OpenStack Nova项目还通过其Python API virDomainBlockRebase使用libvirt blockcopy的变体来创建实时快照Nova image-create。(更多细节在即将发布的博文中)。
二、blockcopy操作有两个阶段
A blockcopy operation has two phases:
(a) All of source disk content is copied (or mirrored) to the destination, this operation can be canceled to revert to the source disk
将源磁盘的所有内容复制(或镜像)到目标磁盘,可以取消此操作以恢复到源磁盘
(b) Once libvirt gets a signal indicating source and destination content are equal, the mirroring job remains awake until an explicit call to virsh blockjob [. . .] --abort is issued to end the mirroring operation gracefully .
If desired, this explicit call to abort can be avoided by supplying --finish option. virsh manual page for verbose details.
一旦libvirt收到指示源内容和目标内容相等的信号,镜像作业将保持清醒,直到发出对virsh blockjob[…] --abort的明确调用,以优雅地结束镜像操作。
如果需要,可以通过提供--finish选项来避免这种对abort的显式调用。详细详细信息的virsh手册页

三、Scenario: Live disk storage migration
场景:热迁移磁盘存储
To illustrate a simple case of live disk storage migration, we’ll use a disk image chain of depth 2:
为了演示实时磁盘存储迁移的简单示例,我们将使用深度为2的磁盘映像链
base <-- snap1 <-- snap2 (Live QEMU)
Once live blockcopy is complete, the resulting status of disk image chain ends up as below:
一旦活块拷贝完成,磁盘映像链的结果状态如下所示
base <-- snap1 <-- snap2
^
|
'------- copy (Live QEMU, pivoted)
I.e. once the operation finishes, ‘copy’ will share the backing file chain of ‘snap1’ and ‘base’. And, live QEMU is now pivoted(转动的) to use the ‘copy’.
例如,一旦操作完成,' copy '将共享备份文件链' snap1 '和' base '。而且,live QEMU现在已经转向使用“副本”。

四、Prepare disk images, backing chain & define the libvirt guest
准备磁盘映像,backing链和定义libvirt guest
[For simplicity, all virtual machine disks are QCOW2 images.]
[为简单起见,所有虚拟机磁盘都是QCOW2映像。]
Create the base image:

$ qemu-img create -f qcow2 base 1G
Edit the base disk image using guestfish, create a partition, make a file-system, add a file to the base image so that we distinguish its contents from its qcow2 overlay disk images:
使用guestfish编辑基本磁盘映像,创建一个分区,创建一个文件系统,添加一个文件到基本映像中,这样我们就可以将它的内容与它的qcow2覆盖的磁盘映像区分开来:
$ guestfish -a base.qcow2
[. . .]
><fs> run
><fs> part-disk /dev/sda mbr
><fs> mkfs ext4 /dev/sda1
><fs> mount /dev/sda1 /
><fs> touch /foo
><fs> ls /
foo
><fs> exit
Create another QCOW2 overlay snapshot ‘snap1’, with backing file as ‘base’:
创建另一个QCOW2覆盖快照“snap1”,备份文件为“base”:
$ qemu-img create -f qcow2 -b base.qcow2 -o backing_fmt=qcow2 snap1.qcow2
Add a file to snap1.qcow2:

$ guestfish -a snap1.qcow2
[. . .]
><fs> run
><fs> part-disk /dev/sda mbr
><fs> mkfs ext4 /dev/sda1
><fs> mount /dev/sda1 /
><fs> touch /bar
><fs> ls /
bar
baz
foo
lost+found
><fs> exit
Create another QCOW2 overlay snapshot ‘snap2’, with backing file as ‘snap1’:
创建另一个QCOW2覆盖快照snap2,备份文件为snap1
$ qemu-img create -f qcow2 -b snap1.qcow2 -o backing_fmt=qcow2 snap2.qcow2
Add another test file ‘baz’ into snap2.qcow2 using guestfish (refer to previous examples above) to distinguish contents of base, snap1 and snap2.
向snap2中添加另一个测试文件“baz”。qcow2使用guestfish(参阅上面的示例)来区分base、snap1和snap2的内容。
Create a simple libvirt XML file as below, with source file pointing to snap2.qcow2 — which will be the active block device (i.e. it tracks all new guest writes):
创建一个简单的libvirt XML文件,如下所示,源文件指向snap2。qcow2 -这将是活动块设备(即它会跟踪所有新的客户写):
$ cat <<EOF > /etc/libvirt/qemu/testvm.xml
<domain type='kvm'>
<name>testvm</name>
<memory unit='MiB'>512</memory>
<vcpu>1</vcpu>
<os>
<type arch='x86_64'>hvm</type>
</os>
<devices>
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2'/>
<source file='/export/vmimages/snap2.qcow2'/>
<target dev='vda' bus='virtio'/>
</disk>
</devices>
</domain>
EOF
Define the guest and start it:

$ virsh define etc/libvirt/qemu/testvm.xml
Domain testvm defined from /etc/libvirt/qemu/testvm.xml
$ virsh start testvm
Domain testvm started

执行磁盘热迁移
Perform live disk migration
Undefine the running libvirt guest to make it transient[*]:
取消定义正在运行的libvirt客户端,使其成为临时的
$ virsh dumpxml --inactive testvm > /var/tmp/testvm.xml
$ virsh undefine testvm
Check what is the current block device before performing live disk migration:
执行热磁盘迁移前,请检查当前的块设备是什么:
$ virsh domblklist testvm
Target Source
------------------------------------------------
vda /export/vmimages/snap2.qcow2

Optionally, display the backing chain of snap2.qcow2:
可选地,显示snap2.qcow2的后台链
$ qemu-img info --backing-chain /export/vmimages/snap2.qcow2
[. . .] # Output removed for brevity

Initiate blockcopy (live disk mirroring):
初始化blockcopy(活跃磁盘镜像):
$ virsh blockcopy --domain testvm vda
/export/blockcopy-test/backups/copy.qcow2
--wait --verbose --shallow
--pivot
Details of the above command:
上面命令的详细信息
It creates copy.qcow2 file in the specified path;
performs a --shallow blockcopy (i.e. the ‘copy’ shares the backing chain 副本”共享后备链) of the current block device (vda);
–pivot will pivot the live QEMU to the ‘copy’.
pivot会把QEMU的活轴转向“副本”
Confirm that QEMU has pivoted to the ‘copy’ by enumerating the current block device in use:
通过枚举当前正在使用的块设备,确认QEMU已经转向' copy ':
$ virsh domblklist testvm
Target Source
------------------------------------------------
vda /export/vmimages/copy.qcow2

Again, display the backing chain of ‘copy’, it should be the resultant chain as noted in the Scenario section above).
同样,显示“copy”的后台链,它应该是上面场景部分提到的结果链)
$ qemu-img info --backing-chain /export/vmimages/copy.qcow2
Enumerate the contents of copy.qcow2:

$ guestfish -a copy.qcow2
[. . .]
><fs> run
><fs> mount /dev/sda1 /
><fs> ls /
bar
foo
baz
lost+found
><fs> quit
(You can notice above: all the content from base.qcow2, snap1.qcow2, and snap2.qcow2 mirrored into copy.qcow2.)
你可以注意到上面:所有的内容都来自base. qcow2 snap1.qcow2, snap2.qcow2镜像到copy.qcow2
Edit the libvirt guest XML to use the copy.qcow2, and define it:

$ virsh edit testvm
# Replace the <source file='/export/vmimages/snap2.qcow2'/>
# with <source file='/export/vmimages/copy.qcow2'/>
[. . .]

$ virsh define /var/tmp/testvm.xml
[*] Reason for the undefining and defining the guest again:
As of writing this, QEMU has to support persistent dirty bitmap — this enables us to restart a QEMU process with disk mirroring intact.
There are some in-progress patches upstream for a while.
Until they are in main line QEMU, the current approach (as illustrated above) is:
make a running libvirt guest transient temporarily, perform live blockcopy, and make the guest persistent again.
(Thanks to Eric Blake, one of libvirt project’s principal developers, for this detail.)

原文地址:https://www.cnblogs.com/potato-chip/p/14202934.html