kvm虚拟机快照技术

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简介

什么是虚拟机快照链(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创建快照

以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了解更多

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

domain是指libvirt创建的虚拟机

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

 

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

 

内置快照介绍(Internal Snapshots)

内置磁盘快照

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

内置系统还原点

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

外置快照介绍(External Snapshots)

外置磁盘快照(External disk snapshot)

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

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

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

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

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

#查看虚拟机信息
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

外置磁盘快照创建

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

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

virsh start centos2
virsh domblklist centos2
Target Source
------------------------------------------------
vda /data_lij/vhosts/centos2.qcow2
hdc -

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

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

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
...
#所使用磁盘已经更新到新创建的磁盘

查看新磁盘centos2_sn1.qcow2信息

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

查看所有外置快照

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

查看当前使用磁盘

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

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

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

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

外置磁盘快照的合并

合并方式

外置快照非常有用,但这里有一个问题就是如何合并快照文件来缩短链的长度,不能直接删除某个快照,因为每个快照都保存有相应的数据
有两种方式实现
blockcommit: 从 top 合并数据到 base (即合并overlays至backing files)
blockpull: 将backing file数据合并至overlay中.从 base 到 top

blockcommit向下合并

blockcommit可以让你将'top'镜像(在同一条backing file链中)合并至底层的'base'镜像,一旦 blockcommit #执行完成,处于最上面的overlay链关系将被自动指向到底层的overlay或base, 这在创建了很长一条链之后用来缩短链长度的时候十分有用.
测试发现:
A qemu1.3以下版本不支持live blockcommit,
B qemu2.0以下版本不支持合并'Active'层(最顶部的overlay,即当前使用磁盘)至backing_files

下面是示意图

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

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

(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

blockpull向上合并

blockpull(qemu中也称作'block stream')可以将backing合并至active,与blockcommit正好相反.
在qemu最新版本2.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合并示意图

使用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

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

查看当前信息

#查看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
#所有的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

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

方法

我们需要删除快照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只被当前链使用)

复制sn2数据到后端sn1

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名字(不复制数据)

复制sn2数据到前段sn3

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

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

链接http://www.cnblogs.com/jython/p/4301954.html

原文地址:https://www.cnblogs.com/guge-94/p/11827390.html