如何复制KVM虚拟机的快照

KVM虚拟机的快照(snapshot)功能可以保存虚拟机运行时的内存状态,恢复快照后虚拟机即可恢复到创建快照时的运行时状态,所有的软件运行状态依旧,类似于游戏中的SL(save/load)大法。我们可以使用快照功能实现很多业务,例如快速恢复沙箱的运行状态,而不用清理环境或是重启虚拟机等待服务一一启动。

但是KVM虚拟机的快照功能却不是很好利用,当需要大规模使用快照时就会发现似乎快照没那么好复制,复制出来的快照往往启动后也会失效,无法恢复,让批量化部署变得很困难。本文介绍了复制KVM虚拟机快照方法,用较低的成本将一个虚拟机的快照复制出来,方便批量部署。

快照命令

快照功能实际上是qemu的功能,这个功能保存了虚拟机的运行时状态,要使用这个功能,要求虚拟机的镜像为qcow2格式,raw格式等格式不支持这个功能。

libvirt作为我们常用的虚拟机管理工具,提供了快捷的方式来创建及恢复快照,这些命令如下:

# 为kvm01虚拟机创建快照
virsh snapshot-create kvm01

# 列出kvm01虚拟机的快照
virsh snapshot-list kvm01

# 恢复kvm01虚拟机到最近的快照
virsh snapshot-revert kvm01 --current

# 恢复kvm01虚拟机到指定的快照
virsh snapshort-revert kvm01 --snapshotname 1515143552

如果有虚拟机的话,可以尝试一把上面的命令,感受下虚拟机快照的效果。

openstack上的快照功能没有保存内存运行时的状态,仅仅保存了磁盘的状态,因此在恢复快照后虚拟机还是会重启,无法恢复到运行时的状态。

快照存储在哪儿?

快照的信息实际上是存到了镜像文件本身的,我们可以使用“qemu-img info”命令来获取到镜像的信息,我们对一个做了快照的镜像执行该命令,此时就可以看到快照的信息:

[root@knktc snapshot]# qemu-img info source.img 
image: source.img
file format: qcow2
virtual size: 20G (21474836480 bytes)
disk size: 3.1G
cluster_size: 65536
backing file: /opt/snapshot/base.img
Snapshot list:
ID        TAG                 VM SIZE                DATE       VM CLOCK
1         1519990436             2.6G 2018-03-02 19:33:56   00:08:27.846
Format specific information:
    compat: 1.1
    lazy refcounts: false

在上面的镜像信息中,“Snapshot list”的部分就标示出了当前这个镜像有一个快照。

看来,我们要复制快照,就只能把做了快照的镜像也给复制一份了。一般虚拟机的镜像都有几G到几十G之大,复制起来比较浪费空间,但qcow2格式的镜像支持backing file功能,即使用一个基础镜像来创建一个镜像,创建出来的镜像仅保存增量信息,这样就大幅度地降低了要复制的文件的体积了。

于是我们就有了这么一个思路:

  1. 创建基础虚拟机镜像;
  2. 使用这个基础镜像创建新的虚拟机,并制作快照;
  3. 复制这个新的虚拟机镜像,达到复制快照的效果。

下面就开始试试这个思路吧。

创建基础虚拟机镜像

这个步骤可以略过,找一个现有的虚拟机,或是重新创建一个虚拟机都可以。

我们假设我们现在已经有了一个虚拟机镜像,名称为“base.img”。

创建新的虚拟机和快照

我们使用基础的虚拟机镜像再创建一个虚拟机镜像,名为“source.img”,命令如下:

qemu-img create -b base.img -f qcow2 source.img

我们把这个虚拟机镜像启动起来(比如使用libvirt创建一个叫source的虚拟机),运行到一个状态,随后创建快照:

# 为source创建一个快照
virsh snapshot-create --domain source

# 命令执行后将会反馈下面的内容
Domain snapshot 1519990436 created

此时快照已经创建好,名称为1519990436(使用时间戳来表示快照的名称)。

为了防止镜像体积持续变大,我们现在把虚拟机给强制关机:

virsh destroy source

为了确认镜像中已包含快照信息,可以使用以下的命令确认下:

qemu-img info source.img

或是直接使用snapshot-list命令来获取虚拟机source的快照信息:

[root@knktc ~]# virsh snapshot-list source
 Name                 Creation Time             State
------------------------------------------------------------
 1519990436           2018-03-02 19:33:56 +0800 running

导出快照配置文件

使用”snapshot-dumpxml”命令可以将刚才的快照配置文件导出为一个xml文件,我们将这个导出的xml文件命名为snapshot.xml:

virsh snapshot-dumpxml --domain source --snapshotname 1519990436 > snapshot.xml

打开我们导出的快照配置文件,我们可以看到以下的内容:

<domainsnapshot>
  <name>1519990436</name>
  <state>running</state>
  <creationTime>1519990436</creationTime>
  <memory snapshot='internal'/>
  <disks>
    <disk name='vda' snapshot='internal'/>
  </disks>
  <domain type='kvm'>
    <name>source</name>
    <uuid>12d3271a-c683-44b2-8244-dd4b53818035</uuid>
    <memory unit='KiB'>4194304</memory>
    <currentMemory unit='KiB'>4194304</currentMemory>
    <vcpu placement='static'>2</vcpu>
    <resource>
      <partition>/machine</partition>
    </resource>
    <os>
      <type arch='x86_64' machine='rhel6.6.0'>hvm</type>
      <boot dev='hd'/>
    </os>
    <features>
      <acpi/>
      <apic/>
      <pae/>
    </features>
    <clock offset='utc'/>
    <on_poweroff>destroy</on_poweroff>
    <on_reboot>restart</on_reboot>
    <on_crash>restart</on_crash>
    <devices>
      <emulator>/usr/libexec/qemu-kvm</emulator>
      <disk type='file' device='disk'>
        <driver name='qemu' type='qcow2' cache='writeback'/>
        <source file='/opt/snapshot/source.img'/>
        <target dev='vda' bus='virtio'/>
        <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
      </disk>
      <controller type='usb' index='0' model='piix3-uhci'>
        <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
      </controller>
      <controller type='pci' index='0' model='pci-root'/>
      <interface type='network'>
        <mac address='52:54:00:15:ec:5b'/>
        <source network='default'/>
        <model type='virtio'/>
        <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
      </interface>
      <input type='tablet' bus='usb'>
        <address type='usb' bus='0' port='1'/>
      </input>
      <input type='mouse' bus='ps2'/>
      <input type='keyboard' bus='ps2'/>
      <graphics type='vnc' port='19000' autoport='no' listen='0.0.0.0'>
        <listen type='address' address='0.0.0.0'/>
      </graphics>
      <video>
        <model type='cirrus' vram='16384' heads='1' primary='yes'/>
        <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
      </video>
      <memballoon model='virtio'>
        <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
      </memballoon>
    </devices>
  </domain>
  <cookie>
  </cookie>
</domainsnapshot>

看着有点眼熟啊对不对?似乎就是在虚拟机的配置文件上面加了点东西嘛。

可以看到,这个配置文件中包含了快照的信息(名称、运行状态)和虚拟机的配置信息(几乎就是虚拟机的配置xml)。有了这个信息,我们可以考虑修 改这个配置文件,应用于我们复制出来的镜像中。

复制快照

要复制快照,我们先要复制镜像,将刚才的source.img复制为我们新的虚拟机需要使用的镜像(我们把它复制为test01.img文件):

cp source.img test01.img

随后我们再创建一个虚拟机test01,使用刚才复制出来的test01.img镜像文件。在define虚拟机后,我们获取下新创建的虚拟机的uuid和mac地址信息。这两个信息一般情况下我们是让libvirt随机创建的,因此需要提前获取到,使用以下命令即可查看新创建的虚拟机的配置:

virsh dumpxml test01

然后,我们拿这个test01虚拟机的信息来修改刚才导出的快照配置文件snaphost.xml,我们需要修改的部分如下:

  1. uuid
  2. 虚拟机名称
  3. 镜像的路径
  4. mac地址
  5. vnc端口

注意!注意!注意!如果以上的几个信息填写得和test01虚拟机的信息不符,将无法使用快照功能!

修改完成后,我们将这个修改完成的快照配置文件为test01虚拟机导入:

# 执行以下命令,让test01虚拟机也能感知到自己体内有个快照
virsh snapshot-create test01 snapshot.xml --redefine

# 执行命令后将会返回以下的信息
Domain snapshot 1519990436 created from 'snapshot.xml'

导入完成!

测试快照

我们可以直接使用snapshot-list命令来列出test01虚拟机的快照信息,可以看到:

[root@knktc ~]# virsh snapshot-list test01
 Name                 Creation Time             State
------------------------------------------------------------
 1519990436           2018-03-02 19:33:56 +0800 running

确实是已经导入了一个快照,快照名称和上文中source虚拟机的快照是一模一样的。

我们尝试着恢复下快照:

virsh snapshot-revert --domain test01 --snapshotname 1519990436

此时连接到虚拟机上看看,刚才保存的运行时状态也都在跑着,成功!

其他

近期在pyajs上写一个libvirt的http wrapper,叫closestack,用于小型化的项目,但是各种事情太多,进度很慢,希望能慢慢搞完吧:https://github.com/pyajs/closestack

转载请注明出处:https://knktc.com/2018/06/12/how-to-duplicate-kvm-snapshot/

评论