首页 » Virtualization » KVM虚拟机快照链创建,合并,删除及回滚研究

KVM虚拟机快照链创建,合并,删除及回滚研究

 

1 QEMU,KVM,libvirt关系

QEMU

QEMU提供了一个开源的服务器全虚拟化解决方案,它可以使你在特定平台的物理机上模拟出其它平台的处理器,比如在X86 CPU上虚拟出Power的CPU,此时的guest OS感觉不到虚拟机的存在,就像运行在物理机上,QEMU可以单独使用模拟CPU和各种外设,也可以作为一个用户空间工具和运行在内核中的KVM结合使用以充分发挥KVM的功能,QEMU的wiki

KVM

KVM是一个基于内核的虚拟机(Linux中一个可加载模块),在硬件支持虚拟化(intel VT,AMD-V)的X86平台上实现了全虚拟化功能,由于用户不能直接操作内核,所以它还需要一个用户空间工具,一个修改过的QEMU,这样用户可以通过QEMU去使用KVM,QEMU专门提供了一些命令工具来操作KVM

qemu-img:用来进行磁盘管理的一个工具

qemu-system-x86_64,是用来专门创建x86平台的虚拟机的命令行工具

libvirt

libvirt是为了更方便地管理平台虚拟化技术而设计的开放源代码的应用程序接口、守护进程和管理工具,它不仅提供了对虚拟化客户机的管理,也提供了对虚拟化网络和存储的管理。尽管libvirt项目最初是为Xen设计的一套API,但是目前对KVM等其他Hypervisor的支持也非常的好。libvirt支持多种虚拟化方案,既支持包括KVM、QEMU、Xen、VMware、VirtualBox等在内的平台虚拟化方案,又支持OpenVZ、LXC等Linux容器虚拟化系统,还支持用户态Linux(UML)的虚拟化。

libvirt其实质就是对针对不同的hypervisor的命令进行了一个封装,libvirt针对不同的开发语言提供了api接口,如python、c等;libvirtd是linux的一个守护进程,使用libvirt必须先启动这个守护进程

因为libvirt是目前使用最为广泛的对KVM虚拟机进行管理的工具和应用程序接口(API),而且一些常用的虚拟机管理工具(如virsh、virt-install、virt-manager等)和云计算框架平台(如OpenStack、OpenNebula、Eucalyptus等)都在底层使用libvirt的应用程序接口

libvirt作为中间适配层,让底层Hypervisor对上层用户空间的管理工具是可以做到完全透明的,因为libvirt屏蔽了底层各种Hypervisor的细节,为上层管理工具提供了一个统一的、较稳定的接口(API)

更多参考这个libvirt简介

下面贴一张图

2 测试物理环境

1 系统版本

Red Hat Enterprise Linux Server release 6.5 (Santiago)

2 libvirt && QEMU rpm版本

1
2
3
4
5
6
7
8
[root@controller2 scripts]# rpm -qa | egrep "(qemu|libvirt)"
qemu-img-0.12.1.2-2.415.el6.3ceph.x86_64
qemu-kvm-tools-0.12.1.2-2.415.el6.3ceph.x86_64
libvirt-python-0.10.2-29.el6.x86_64
gpxe-roms-qemu-0.9.7-6.10.el6.noarch
libvirt-0.10.2-29.el6.x86_64
qemu-kvm-0.12.1.2-2.415.el6.3ceph.x86_64
libvirt-client-0.10.2-29.el6.x86_64

3 关于QEMU版本

rhel6上qemu默认版本为0.12,它不支持开机状态的blockcommit,目前最新版本2.1.2可以支持,这部分可以参考qemu官网的changelog

支持开机状态的快照合并

#qemu 1.3版本changelog:

A new block job is supported: live block commit (also known as "snapshot deletion") moves data from an image to another in the backing file chain. With the current implementation of QEMU 1.3, the "source" image may not be the active one.

支持当前avtive快照的合并

#qemu 2.0版本changelog

Live snapshot merge (...-commit) can be used to merge the active layer of an image into one of the snapshots

3.什么是虚拟机快照链(snapshot chains)

虚拟机快照保存了虚拟机在某个指定时间点的状态(包括操作系统和所有的程序),利用快照,我们可以恢复虚拟机到某个以前的状态,比如测试软件的时候经常需要回滚系统

快照链就是多个快照组成的关系链,这些快照按照创建时间排列成链,像下面这样,本文章要解释的就是怎么创建这条链,链中快照的相互关系,缩短链,以及如何利用这条链回滚我们的虚拟机到某个状态

base-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镜像的能力,

解释下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创建快照

.-----------.   .-----------.   .------------.  .------------.    .------------.    /------------\
|           |   |           |   |            |  |            |    |            |    |            |
|centosbase |<---  centos1  |<---centos1_sn1 <--- centos1_sn2 <--- centos1_sn3 |<-- |centos1_sn4 |
|           |   |(overlays1)|   |            |  |            |    |            |    |  (Active)  |
'-----------'   '-----------'   '------------'  '------------'    '------------'    \------------/
   ^    ^
   |    |
   |    |       .-----------.    .------------.
   |    |       |           |    |            |
   |    '-------| centos2   |<---|centos2_sn1 |   ...
   |            |(overlays2)|    |            |
   |            '-----------'    '------------'
   |
   |
   |            .-----------.    .------------.
   |            |           |    |            |
   '------------| centos3   |<---|centos3_sn1 |   ...
                |(overlays3)|    |            |
                '-----------'    '------------'

以CentOS系统来说,我们制作了一个qcow2格式的虚拟机镜像,想要以它作为模板来创建多个虚拟机实例,有两种方法创建实例
A.每新建一个实例,把centosbase模板复制一份,创建速度慢
B.使用copy-on-write技术(qcow2格式的特性),创建基于模板的实例,创建速度很快,可以查看磁盘文件大小比较一下

上图中centos1,centos2,centos3等是基于centosbase模板创建的虚拟机(guest),接下来做的测试需要用到,centos1_sn1,centos1_sn2,centos1_sn3等是实例centos1的快照链

我们可以只用一个backing files创建多个虚拟机实例(overlays),然后可以对每个虚拟机实例做多个快照

注意:backing files总是只读的文件,换言之,一旦新快照被创建,他的后端文件就不能更改(快照依赖于后端这种状态),参考后面的blockcommit了解更多

4.为虚拟机创建瘦装备实例(domain)

domain是指libvirt创建的虚拟机

qemu-img是QEMU的磁盘管理工具,qemu编译之后,默认会提供这个工具,如下关系链

1
2
3
               /----- <- [centos1.qcow2] <- [centos1_A.qcow2] <- [centos1_B.qcow2]
[(centosbase)]|                
               \----- <- [centos2.qcow2] <- [centos2_A.qcow2] <- [centos2_B.qcow2]
1
2
3
#使用模板镜像centosbase(backing file)创建两个虚拟机(基于centosbase),20G不是必须的参数
qemu-img create -b centosbase.qcow2 -f qcow2 centos1.qcow2 20G
qemu-img create -b centosbase.qcow2 -f qcow2 centos2.qcow2 20G

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

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

5.内置快照介绍(Internal Snapshots)

5.1 内置磁盘快照

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

5.2 内置系统还原点

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

6 外置快照介绍(External Snapshots)

6.1 外置磁盘快照(External disk snapshot)

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

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

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

7.内置磁盘快照创建,回滚及删除

使用centos1这个虚拟机测试内置磁盘快照的操作(参考第3节原理图)
#此虚拟机所使用磁盘为centos1.qcow2,其backing file为centosbase.qcow2,创建过程中可以观察磁盘大小的变化

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

8 外置磁盘快照创建

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

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

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

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

2.创建外置快照1(centos2启动)

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

3.查看新磁盘centos2_sn1.qcow2信息

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

4.查看所有外置快照

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

5.查看当前使用磁盘

1
2
virsh domblklist centos2
vda /data_lij/vhosts/centos2_sn4.qcow2

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

6.查看虚拟机centos2的完整快照链(centos2_sn4.qcow2为当前使用磁盘)

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

9.外置磁盘快照的合并

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

#下面是示意图

上面这张图中,上面是我们之前给centos2虚拟机创建的4个相互依赖的外置磁盘快照,如下表示关系

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

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

1
2
3
4
5
6
(method-a):
virsh blockcommit --domain f17 vda --base /export/vmimages/sn1.qcow2 --top /export/vmimages/sn3.qcow2 --wait --verbose
或者
(method-b):
virsh blockcommit --domain centos2 vda --base centos2_sn2.qcow2 --top centos2_sn3.qcow2 --wait --verbose
virsh 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正好相反.
#在qemu最新版本2.1.2上测试发现,当前只能将backing file合并至正在使用的active中

1
2
centosbase <-- centos2 <-- centos2_sn1 <-- centos2_sn2 <-- centos2_sn3 <-- centos2_sn4(active)
#在上面快照链中,可以合并sn1/sn2/sn3到sn4(active),但不能合并sn1/sn2到sn3,因为sn3非当前active磁盘

#下面是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

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

#查看当前信息

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

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

centosbase <-- centos2 <-- centos2_sn1 <-- centos2_sn2 <-- centos2_sn3 <-- centos2_sn4

centosbase --> centos2 --> centos2_sn1 --> centos2_sn2 --> centos2_sn3 --> centos2_sn4

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

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

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

1.方法

我们需要删除快照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.(1): 复制sn2数据到后端sn1

1
2
qemu-img commit centos2_sn2.qcow2
qemu-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.(2): 复制sn2数据到前段sn3

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

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

原文链接:KVM虚拟机快照链创建,合并,删除及回滚研究,转载请注明来源!

0