天天看點

KVM虛拟機快照研究(一)

      KVM虛拟機的快照用來儲存虛拟機在某個時間點的記憶體、磁盤或者裝置狀态,如果将來有需要可以把虛拟機的狀态復原到這個時間點。

根據被做快照的對象不同,快照可以分為磁盤快照和記憶體快照,兩者加起來構成了一個系統還原點,記錄虛拟機在某個時間點的全部狀态;根據做快照時虛拟機是否在運作,快照又可以分為線上快照和離線快照。

磁盤快照根據存儲方式的不同,又分為内部快照和外部快照:内部快照隻支援qcow2格式的虛拟機鏡像,把快照及後續變動都儲存在原來的qcow2檔案内;外部快照在建立時,快照被儲存在單獨一個檔案中,建立快照時間點之後的資料被記錄到一個新的qcow2檔案中,原鏡像檔案成為新的qcow2檔案的backing file(隻讀),在建立多個快照後,這些檔案将形成一個鍊——backing chain。外部快照同時支援raw和qcow2格式的虛拟機鏡像。

下文将分别具體介紹不同類型的KVM虛拟機快照。

操作環境:

l  作業系統:

[root@localhost ~]# cat   /etc/redhat-release

CentOS Linux release 7.4.1708 (Core)

l  Libvirt版本:

[root@localhost ~]# libvirtd --version

libvirtd (libvirt) 3.2.0

l  qemu版本:

[root@localhost ~]# rpm -qa|grep qemu-kvm

qemu-kvm-common-ev-2.3.0-29.1.el7.x86_64

qemu-kvm-ev-2.3.0-29.1.el7.x86_64

centos7.4的預設yum源中的qemu-kvm不支援線上建立外部快照,需要安裝Redhat的qemu-kvm-ev,安裝方法:

1.      配置yum源

[root@localhost ~]# cat   /etc/yum.repos.d/qemu-kvm-rhev.repo

[qemu-kvm-rhev]

name=oVirt rebuilds of qemu-kvm-rhev

baseurl=http://resources.ovirt.org/pub/ovirt-3.5/rpm/el7Server/

mirrorlist=http://resources.ovirt.org/pub/yum-repo/mirrorlist-ovirt-3.5-el7Server

enabled=1

skip_if_unavailable=1

gpgcheck=0

2.      安裝

[root@localhost ~]# yum install qemu-kvm-rhev -y

測試機上有一台虛拟機

[root@localhost ~]# virsh list

 Id      Name                             State

----------------------------------------------------

10      vm                             running

虛拟機的磁盤檔案為系統盤/data/vm.img,資料盤/data/data.img。

記憶體快照

1.      建立快照

指令:virsh save vm vm.snapshot1

[root@localhost ~]# virsh save vm   vm.snapshot1

Domain vm saved to vm.snapshot1

建立完後虛拟機會關機:

[root@localhost ~]# virsh list --all

 -       vm                             shut off

2.      復原快照

指令:virsh restore vm.snapshot1

[root@localhost ~]# virsh restore   vm.snapshot1

Domain restored from vm.snapshot1

 11      vm                             running

注:

1.      隻能對關機狀态的虛拟機進行復原快照;

2.      記憶體快照做完後,如果虛拟機磁盤檔案發生修改,可能會導緻corruption。

磁盤内部快照

磁盤内部快照可以在虛拟機開機狀态建立,但是建立過程中虛拟機處于paused狀态,

指令:virsh snapshot-create-as --domain vm --name vm1

這條指令執行後,虛拟機會變成paused狀态

 13      vm                             paused

等快照建立完成,會重新變回running。

2.      檢視快照

指令:virsh snapshot-list –domain vm

[root@localhost ~]# virsh snapshot-list   --domain vm

 Name                 Creation Time             State

------------------------------------------------------------

 vm1                  2018-03-06 10:37:57 +0800   running

快照復原:virsh snapshot-revert --domain vm --snapshotname vm1

快照删除:virsh snapshot-delete --domain vm --snapshotname vm1

磁盤内部快照有2個缺點:

1.      隻支援qcow2格式的鏡像檔案;

2.      建立快照虛拟機會paused,有停機時間,對于不能停機的線上業務來說是無法接受的。

磁盤外部快照

原理

假設虛拟機磁盤鏡像檔案為base,建立一個外部快照snapshot1,這時候的鏡像之間的關系backing chain如下:

base<-snapshot1*

“*”表示目前active狀态的鏡像,base變為隻讀,snapshot1以base為backing file,虛拟機所有寫入都發生在snapshot1,如果再建立一個外部快照snapshot2,backing chain會變成:

base<-snapshot1<-snapshot2*

snapshot2又以snapshot1為backing file,現在base和snapshot1都變成了隻讀。繼續建立快照會加長這個backing chain:

base<-snapshot1<-snapshot2<-snapshot3<-snapshot4*

如果要復原某個快照,就要把虛拟機使用的鏡像指向該快照檔案的backing file。例如,復原到snapshot2,就要把虛拟機的鏡像改為snapshot1;復原到snapshot1,則要把虛拟機的鏡像改為base。復原到snapshot1會導緻snapshot1之後的所有快照失效,因為他們在backing chain上遊的backing file發生了變化(backing file隻能是隻讀,如果資料發生變化,下遊鏡像也會失效)。

随着快照數量變多,backing chain也會越來越長,變得難以維護。如果有些快照已經沒用了可以進行删除。縮短這條鍊通常有兩種思路:

1.      blockcommit,從top檔案合并資料到base(下遊鏡像向backing file合并,稱為“commit”);

2.      blockpull,從base檔案合并資料到top(從backing file向下遊鏡像合并,稱為“pull”)。截止目前隻能将backing file合并至目前的active的鏡像中,也就是說還不支援指定top的合并。

在上面的backing chain中,如果我們要删除snapshot2,方法如下:

1.      blockcommit:把snapshot2的資料合并到snapshot1,合并完後backing chain變成了

base<-snapshot1<-snapshot2(内容為snapshot2+snapshot3)<-snapshot4*

2.      blockpull:把snapshot2的資料合并到snapshot3,合并完後backing chain變成了

base<-snapshot1<-snapshot3(内容為snapshot2+snapshot3)<-snapshot4*

具體操作

1.      建立外部快照

指令:virsh snapshot-create-as --domain vm --name snapshot1 --disk-only --atomic --no-metadata

--disk-only 有這個參數,snapshot-create-as指令就會建立磁盤外部快照;

--atomic 如果虛拟機有多個磁盤,則把為虛拟機所有磁盤建立快照的操作當做一個原子操作,要麼全部成功,要麼全部失敗;

--no-metadata 不讓libvirt記錄快照的中繼資料。這個參數不是必須的,但是強烈建議使用,目前libvirt對外部快照支援不完整,隻能建立,不能删除和復原,如果要删除一個有外部快照的虛拟機,會出現以下報錯:

[root@localhost ~]# virsh undefine vm

error: Failed to undefine domain test

error: Requested operation is not valid:   cannot delete inactive domain with 1 snapshots

加上這個參數後,libvirt不再管理外部快照,删除和復原都不會受影響了。

快照建立成功後,在虛拟機磁盤檔案目錄下會多出2個新檔案vm.snapshot1和data.snapshot1,分别是系統盤和資料盤的快照檔案,檢視鏡像資訊可以看出,它們分别以原鏡像為backing file,與之前原理中分析的一緻:

[root@localhost data]# qemu-img info   vm.snapshot1

image: vm.snapshot1

file format: qcow2

virtual size: 20G (21474836480 bytes)

disk size: 3.4M

cluster_size: 65536

backing file: /data/vm.img

backing file format: qcow2

Format specific information:

      compat: 1.1

      lazy refcounts: false

      refcount bits: 16

      corrupt: false

[root@localhost data]# qemu-img info   data.snapshot1

image: data.snapshot1

virtual size: 1.0G (1073741824 bytes)

disk size: 196K

backing file: /data/data.img

corrupt: false

建立完後,虛拟機xml檔案中使用的磁盤檔案會libvirt自動被改成這兩個新檔案,這兩個新檔案處于active狀态,原鏡像變為隻讀。

<disk type='file' device='disk'>

        <driver name='qemu' type='qcow2' cache='none' io='native'/>

        <source file='/data/vm.snapshot1'/>

        <target dev='vda' bus='virtio'/>

        <address type='pci' domain='0x0000' bus='0x00' slot='0x04'   function='0x0'/>

      </disk>

      <disk type='file' device='disk'>

        <source file='/data/data.snapshot1'/>

        <target dev='vdb' bus='virtio'/>

        <address type='pci' domain='0x0000' bus='0x00' slot='0x07'   function='0x0'/>

Libvirt目前不支援復原外部快照,隻能純手工操作。為了證明在復原快照後虛拟機确實回到了快照記錄的狀态,我們在虛拟機中在/root下建立一個空檔案test。然後關閉虛拟機并把虛拟機的磁盤改回vm.img和data.img,開機後會發現/root/test不見了,可以證明虛拟機檔案系統回到了建立快照的時間點。

由上面的操作我們可以得出結論:復原到某個快照,就是把虛拟機目前磁盤檔案改為這個快照檔案的backing file;快照名和快照檔案名并不對應,例如建立snapshot1後産生的檔案vm.snapshot1中記錄的并不是快照snapshot1的内容,它的backing file才是。在下面介紹删除快照時,牢記這點尤其重要。

3.      删除快照

在原理中已經介紹過,删除快照有blockcommit和blockpull兩種思路,由于blockpull不支援指定top的合并,下面将隻介紹blockcommit方式。我們先為虛拟機vm多建立幾個快照,現在快照鍊為(以下操作都以系統盤為例,資料盤同理):

qemu-img指令也可以檢視鍊關系:

[root@localhost   data]# qemu-img info --backing-chain vm.snapshot4

image:   vm.snapshot4

virtual size:   20G (21474836480 bytes)

disk size:   452K

cluster_size:   65536

backing file:   /data/vm.snapshot3

backing file   format: qcow2

Format   specific information:

    compat: 1.1

    lazy refcounts: false

    refcount bits: 16

    corrupt: false

image:   /data/vm.snapshot3

file format:   qcow2

disk size:   196K

backing file:   /data/vm.snapshot2

image:   /data/vm.snapshot2

backing file:   /data/vm.img

image:   /data/vm.img

disk size:   1.5G

    compat: 0.10

現在我們要删除snapshot2,根據復原快照時得出的結論,要復原到snapshot2就是把虛拟機磁盤指向vm.snapshot1,是以删除snapshot2就要在不影響backing chain中其他檔案的前提下,把vm.snapshot2的内容合并到vm.snapshot1,vm.snapshot1的内容發生了改變,也就不能復原到snapshot2了,達到了删除快照的目的。操作指令如下:

virsh blockcommit --domain vm vda --base /data/vm.snapshot1 --top /data/vm.snapshot2 --wait –verbose

virsh blockcommit --domain vm vdb --base /data/data.snapshot1 --top /data/data.snapshot2 --wait –verbose

合并完後,使用qemu-img指令再次檢視檔案資訊可以發現,vm.snapshot2已經不在backing chain中了:

[root@localhost data]# qemu-img info --backing-chain vm.snapshot4

image: vm.snapshot4

disk size: 1.1M

backing file: /data/vm.snapshot3

    compat: 1.1

image: /data/vm.snapshot3

disk size: 388K

backing file: /data/vm.snapshot1

image: /data/vm.snapshot1

disk size: 1.5M

image: /data/vm.img

disk size: 1.5G

總結

三種快照中,隻有磁盤外部快照可以不停機建立,是以這種快照最符合我們平時的需求,後續研究也重點關注外部快照。不幸的是libvirt對外部快照的支援太弱,大部分操作需要我們人腦思考、手工操作。接下來研究的重點有以下幾點:

1.      測試外部快照建立時是否真正零停機時間;

繼續閱讀