一、有关虚拟机快照链(snapshot chains)

1、snapshot chains

虚拟机快照保存了虚拟机在某个指定时间点的状态(包括操作系统和所有的程序),利用快照,我们可以恢复虚拟机到某个以前的状态,比如测试软件的时候经常需要回滚系统。快照链就是多个快照组成的关系链,这些快照按照创建时间排列成链,像下面这样,本文章要解释的就是怎么创建这条链,链中快照的相互关系,缩短链,以及如何利用这条链回滚我们的虚拟机到某个状态。

1base-image<--guest1<--snap1<--snap2<--snap3<--snap4<--当前(active)

如上,base-image是制作好的一个qcow2格式的磁盘镜像文件,它包含有完整的OS以及引导程序,现在以这个base-image为模板创建多个虚拟机,简单点方法,每创建一个虚拟机我们就把这个镜像完整复制一份,但这种做法效率底下,满足不了生产需要,这是就用到了qcow2镜像的特性copy-on-write。qcow2(qemu copy-on-write)格式镜像支持快照,具有创建一个base-image,以及在base-image(backing file)基础上创建多个copy-on-write overlays镜像的能力

注:qemu 1.3版本以后支持开机状态的快照合并;qemu 2.0版本以后支持当前avtive快照的合并

2、backing file和overlay

上面那条链中,我们为base-image创建一个guest1,那么此时base-image就是guest1的backing file,guest1就是base-image的overlay,同理,为guest1虚拟机创建了一个快照snap1,此时guest1就是snap1的backing file,snap1是guest1的overlay,backing files和overlays十分有用,可以快速的创建瘦装备实例,特别是在开发测试过程中可以快速回滚到之前某个状态。

如下,我们有一个centosbase的原始镜像(包含完整OS和引导程序),现在用它作为模板创建多个虚拟机,每个虚拟机都可以创建多个快照组成快照链,当然不能直接为centosbase创建快照:

kvm-overlays-snapshot
kvm-overlays-snapshot

以CentOS系统来说,我们制作了一个qcow2格式的虚拟机镜像,想要以它作为模板来创建多个虚拟机实例,有两种方法创建实例

  • A.每新建一个实例,把centosbase模板复制一份,创建速度慢
  • B.使用copy-on-write技术(qcow2格式的特性),创建基于模板的实例,创建速度很快,可以查看磁盘文件大小比较一下

上图中centos1,centos2,centos3等是基于centosbase模板创建的虚拟机(guest),接下来做的测试需要用到,centos1后面的snap1,centos1 snap2,centos1_snap3等是实例centos1的快照链,我们可以只用一个backing files创建多个虚拟机实例(overlays),然后可以对每个虚拟机实例做多个快照。注意:backing files总是只读的文件,换言之,一旦新快照被创建,他的后端文件就不能更改(快照依赖于后端这种状态),参考后面的blockcommit了解更多。

二、为虚拟机创建瘦实例(domain)

domain是指libvirt创建的虚拟机,qemu-img是QEMU的磁盘管理工具,qemu编译之后,默认会提供这个工具,利用该工具,可以实现如下关系链:

qemu-img-baseimg
qemu-img-baseimg

使用模板镜像centosbase(backing file)创建两个虚拟机(基于centosbase),20G不是必须的参数

1qemu-img create -b centosbase.qcow2 -f qcow2 centos1.qcow2 20G
2qemu-img create -b centosbase.qcow2 -f qcow2 centos2.qcow2 20G

当不指定后面的大小时,新创建的image文件大小和baseimage大小相等。

现在创建出来的centos1和centos2都可以用来启动一个虚拟机,因为他们依赖于backing file,所以这两个磁盘只有几百个字节大小,只有新的文件才会被写入此磁盘:

1#查看镜像信息,包括虚拟磁盘大小,实际占用空间,backing file
2qemu-img info centos1.qcow2

三、内置快照(Internal Snapshots)

1、内置磁盘快照

单个qcow2镜像文件存储快照点的磁盘状态,没有新磁盘文件产生,虚拟机运行状态和关闭状态都可以创建,Libvirt 使用 ‘qemu-img’ 命令创建关机状态的磁盘快照。

2、内置系统还原点

使用virsh save/restore命令,可以在虚机开机状态下(内存)保存内存状态,设备状态和磁盘状态到一个指定文件中,还原的时候虚机关机,然后restore回去。多用于测试场景中,我们经常需要不断的将vm还原到某个起点,然后重新开始部署和测试。

3、内置磁盘快照创建,回滚及删除

此虚拟机所使用磁盘为centos1.qcow2,其backing file为centosbase.qcow2,创建过程中可以观察磁盘大小的变化(具体可以参看本文第一张图:)

 1#查看虚拟机信息
 2qemu-img info centos1.qcow2
 3#创建快照1(centos1运行时)
 4virsh snapshot-create-as centos1 centos1_sn1 centos1_sn1-desc
 5#创建快照2(centos1关闭)
 6virsh shutdown centos1
 7virsh snapshot-create-as centos1 centos1_sn2 centos1_sn2-desc
 8#查看所有快照
 9virsh snapshot-list centos1
10Name Creation Time State
11------------------------------------------------------------
12centos1_sn1 2016-06-15 16:16:23 +0800 running
13centos1_sn2 2016-06-15 16:18:38 +0800 shutoff
14centos1_sn3 2016-06-15 16:19:59 +0800 shutoff
15centos1_sn4 2016-06-15 16:21:22 +0800 running
16#running表示在虚拟机开启时创建
17#快照回滚
18virsh snapshot-revert --domain centos1 centos1_sn1
19virsh snapshot-revert --domain centos1 centos1_sn3
20#内置磁盘快照可以随意回滚,比如先回滚到sn1,在回滚到sn3都是OK的
21#注意一点是虚拟机开启状态下,不能回滚到State为running的快照点
22#快照删除
23virsh snapshot-delete centos1 centos1_sn2
24或者
25virsh snapshot-delete --domain centos1 --snapshotname centos1_sn2

四、外置快照(External Snapshots)

1、 外置磁盘快照(External disk snapshot)

当一个快照被创建时,创建时当前的状态保存在当前使用的磁盘文件中,即成为一个backing file,此时一个新的overlay被创建出来保存以后写入的数据。

2、 外置系统还原点(External system checkpoint)

虚拟机的磁盘状态将被保存到一个文件中,内存和设备的状态将被保存到另外一个新的文件中。

3、 外置磁盘快照创建

使用centos2这个虚拟机测试外置磁盘快照的操作(参考第一张图),此虚拟机所使用磁盘为centos2.qcow2,虚拟机开启:

首先启动centos2虚拟机,查看当前所使用磁盘

1virsh start centos2
2virsh domblklist centos2
3Target Source
4------------------------------------------------
5vda /data/vhosts/centos2.qcow2
6hdc -

可以看到,当前所使用磁盘为centos2.qcow2,之前说过,外置磁盘快照创建时,会保存正在使用磁盘作为backing file(此磁盘不再接受新数据,只保存快照前的数据),并创建一个新的磁盘作为overlays以等待写入新数据。

4、创建外置快照1(centos2启动)

1virsh snapshot-create-as --domain centos2 centos2_sn1 centos2_sn1-desc --disk-only --diskspec vda,snapshot=external,file=/data/vhosts/centos2_sn1.qcow2 --atomic
2#查看快照
3virsh snapshot-list centos2
4#查看centos2当前所使用磁盘
5virsh domblklist centos2
6...
7vda /data/vhosts/centos2_sn1.qcow2
8...
9#所使用磁盘已经更新到新创建的磁盘

5、查看新磁盘centos2_sn1.qcow2信息

1qemu-img info centos2_sn1.qcow2
2...
3backing file: /data/vhosts/centos2.qcow2
4backing file format: qcow2
5...
6#其backing file为创建快照前使用的磁盘centos2.qcow2
7#快照2,3(centos2关闭)
8virsh snapshot-create-as --domain centos2 centos2_sn2 centos2_sn2-desc --disk-only --diskspec vda,snapshot=external,file=/data/vhosts/centos2_sn2.qcow2 --atomic
9virsh snapshot-create-as --domain centos2 centos2_sn3 centos2_sn3-desc --disk-only --diskspec vda,snapshot=external,file=/data/vhosts/centos2_sn3.qcow2 --atomic

6、查看所有外置快照

1virsh snapshot-list centos2
2Name Creation Time State
3------------------------------------------------------------
4centos2_sn1 2016-06-15 16:35:44 +0800 disk-snapshot
5centos2_sn2 2016-06-15 16:41:39 +0800 shutoff
6centos2_sn3 2016-06-15 16:43:06 +0800 shutoff
7centos2_sn4 2016-06-15 16:44:46 +0800 shutoff

7、查看当前使用磁盘

virsh domblklist centos2
vda /data/vhosts/centos2_sn4.qcow2

虚拟机centos2使用的是最后一个快照的磁盘(称作active),重点要理解的是快照之间是相互依赖的(上一个依赖下一个),每一部分都保存有数据,所有的快照合起来保存虚拟机的全部数据。

8、查看虚拟机centos2的完整快照链

centos2_sn4.qcow2为当前使用磁盘:

1qemu-img info --backing-chain centos2_sn4.qcow2

五、外置磁盘快照的合并

1、合并方式

外置快照非常有用,但这里有一个问题就是如何合并快照文件来缩短链的长度,不能直接删除某个快照,因为每个快照都保存有相应的数据。有两种方式实现:

  • blockcommit: 从 top 合并数据到 base (即合并overlays至backing files)
  • blockpull: 将backing file数据合并至overlay中.从 base 到 top

2、 blockcommit向下合并

blockcommit可以让你将’top’镜像(在同一条backing file链中)合并至底层的’base’镜像,一旦 blockcommit #执行完成,处于最上面的overlay链关系将被自动指向到底层的overlay或base, 这在创建了很长一条链之后用来缩短链长度的时候十分有用。注意:

A qemu1.3以下版本不支持live blockcommit,
B qemu2.0以下版本不支持合并’Active’层(最顶部的overlay,即当前使用磁盘)至backing_files

top-to-base
top-to-base

上图是我们之前给centos2虚拟机创建的4个相互依赖的外置磁盘快照,现在我们想要实现将中间的快照进行合并,并用如下表示关系

1当前: [base] <- sn1 <- sn2 <- sn3 <- sn4(当前使用磁盘)
2目标: [base] <- sn1 <--------------- sn4

我们需要做的是合并sn2,sn3到sn1中,并删除sn2,sn3快照,下面有两种方式:

1(method-a):
2virsh blockcommit --domain f17 vda --base /export/vmimages/sn1.qcow2 --top /export/vmimages/sn3.qcow2 --wait --verbose
3或者
4(method-b):
5virsh blockcommit --domain centos2 vda --base centos2_sn2.qcow2 --top centos2_sn3.qcow2 --wait --verbose
6virsh blockcommit --domain centos2 vda --base centos2_sn1.qcow2 --top centos2_sn2.qcow2 --wait --verbose

注: 如果手工执行*qemu-img*命令完成的话, 现在还只能用method-b. 我们还可以让centos2_sn4(active)直接指向centos2 。

3、 blockpull向上合并

blockpull(qemu中也称作’block stream’)可以将backing合并至active,与blockcommit正好相反。在qemu2.1.2上测试发现,当前只能将backing file合并至正在使用的active中:

centosbase <– centos2 <– centos2_sn1 <– centos2_sn2 <– centos2_sn3 <– centos2_sn4(active)

注:在上面快照链中,可以合并sn1/sn2/sn3到sn4(active),但不能合并sn1/sn2到sn3,因为sn3非当前active磁盘。

下面是blockpull合并示意图:

kvm-blockpull
kvm-blockpull

使用blockpull我们可以将centos2_sn1/2/3中的数据合并至active层,最终centos2将变成active的直接后端。我们需要做的是合并sn1,sn2,sn3到sn4(active)中,并删除sn1,sn2,sn3快照,如下表示关系:

当前: [base(centos2)] <- sn1 <- sn2 <- sn3 <- sn4(当前使用磁盘)
目标: [base(centos2)] <———————- sn4

实现命令如下:

1virsh blockpull --domain centos_2 --path /data/vhosts/centos2_sn4.qcow2 --base /data/vhosts/centos2.qcow2 --wait --verbose
2#清理掉不用的快照
3virsh snapshot-delete --domain centos2 centos2_sn1 --metadata
4virsh snapshot-delete --domain centos2 centos2_sn2 --metadata
5virsh snapshot-delete --domain centos2 centos2_sn3 --metadata

查看当前信息

1#查看centos2的快照
2virsh snapshot-list centos2
3#查看centos2当前使用磁盘
4virsh domblklist centos2
5#查看快照sn4的backing file
6qemu-img info centos2_sn4.qcow2

如果要迁移虚拟机centos2,需要将所有backing files合并至centos2_sn4(active),然后迁移centos2_sn4(active)至目的位置:

1#所有的backing files 都合并到centos2_sn4(active)
2virsh blockpull --domain centos2 --path /data_lij/vhosts/centos2_sn4.qcow2 --wait --verbose
3qemu-img info centos2_sn4.qcow2

合并之后,centos2_sn4是一个完整的镜像,包括centosbase,sn1/2/3所有的数据,此时其不再需要backing files。

六、外置快照的删除(qemu-img commit/rebase)

1、目标删除快照sn2

我们需要删除快照sn2,示例图如下:

当前: [centosbase] <– centos2 <– centos2_sn1 <– centos2_sn2 <– centos2_sn3 <– centos2_sn4(当前使用磁盘)
目标: [centosbase] <– centos2 <– centos2_sn1 <—————— centos2_sn3 <– centos2_sn4(当前使用磁盘)

现在删除第二个快照(sn2).有两种方式:

(1): 复制sn2数据到后端sn1,将会commit所有sn2中的数据到sn2的backing file(sn1),和virsh blockcommit类似
(2): 复制sn2数据到前段sn3,将会commit所有sn2中的数据到sn2的overlays,和virsh blockpull类似

注意: 必须保证sn1没有被其他快照作为后端(即centos2_sn1只被当前链使用)

2、复制sn2数据到后端sn1

1qemu-img commit centos2_sn2.qcow2
2qemu-img rebase -u -b centos2_sn1.qcow2 centos2_sn3.qcow2     #让sn3指向sn1

现在sn1中包含了之前的sn1/sn2中的数据,所以此时不再需要sn2中的数据,直接让sn3指向sn1即可,可以直接删除sn2。

注意: -u代表’Unsafe mode’ — 此模式下仅仅修改了指向到的backing file名字(不复制数据)。

3、复制sn2数据到前段sn3

1qemu-img rebase -b centos2_sn1.qcow2 centos2_sn3.qcow2

未使用-u模式的rebase将把数据也一并合并过去,即把sn2的数据写入到sn3并修改sn3指向sn1,此为默认模式。rebase是向前段合并,commit是向后端合并。

七、其他

在rhev、openstack等平台中,使用的快照功能大都是基于外置快照的形式。这里需要特别注意一点,KVM的快照不要和Vmware的快照混为一谈,Vmware的所有快照可以理解为都是基于baseimage,创建的overlays,删除任一个快照都其他快照的使用和还原都不会有影响,而KVM不同,其快照之间存在链式关系,基中任一环节出现问题,都会出现无法还原到之间状态。当然,平时使用时,可能vmware更便捷,但KVM快照更节省空间。

参考页面:

https://kashyapc.fedorapeople.org/virt/lc-2012/snapshots-handout.html

kvm虚拟化小结(七)内部快照Internal snapshot

kvm虚拟化小结(八)外部快照External snapshot