1 快照的概念
一般對快照的理解就是能夠將系統還原到某個瞬間,這就是快照的作用。
快照針對要保存的數據分為內存快照和磁盤快照,內存快照就是保存當前內存的數據,磁盤快照就是保存硬盤的數據。
快照針對保存方式又分為內部快照和外部快照。
內部快照:是指快照信息和虛擬機存在同一個qcow2鏡像中,使用單個的 qcow2 的文件來保存快照和快照之后的改動。這種快照是 libvirt 的默認行為,現在的支持很完善(創建、回滾和刪除),但是只能針對 qcow2 格式的磁盤鏡像文件,而且其過程較慢等。
外部快照:是指做快照時原虛擬機的disk將變為readonly的模板鏡像,然后會新建一個qcow2文件來記錄與原模板鏡像的差異數據,外部快照的結果是形成一個qcow2文件鏈:original <- snap1 <- snap2 <- snap3
2 主流libvirt快照實現介紹
2.1 libvirt的內部快照操作
以下是利用libvirt的virsh工具來創建一些內置快照:
創建虛擬機快照:
virsh snapshot-create-as --name test001 --description 'abc' instance-00000001
列出虛擬機的快照:
virsh snapshot-list instance-00000001
查看某個快照信息:
virsh snapshot-dumpxml instance-00000001 test001
回滾到某個快照:
virsh snapshot-revert instance-00000001 test001
刪除某個快照:
virsh snapshot-delete instance-00000001 test001
其實這些其實現的本質是在鏡像內做一些標記,內存狀態數據則保存到某一個磁盤鏡像文件內,使用以下命令可以看到在該鏡像做的標記:
qemu-img info /var/lib/nova/instances/87985777-f83d-4fff-9723-025c2b889895/disk
2.2 libvirt的外部快照操作
可以使用 “--memspec” 和 “--diskspec” 參數來給內存和磁盤外部快照。這時候,在獲取內存狀態之前需要 Pause 虛機,就會產生服務的 downtime。
比如:virsh snapshot-create-as instance-00000001 livesnap2 --memspec /home/livesnap2mem,snapshot=external --diskspec vda,snapshot=external
virsh snapshot-dumpxml instance-00000001 livesnap2可以看到具體外置存放位置信息
但是libvirt現在還不支持回滾和刪除外置快照,如下
virsh snapshot-revert instance-00000001 livesnap2
error: unsupported configuration: revert to external snapshot not supported yet
3 OpenStack原生虛擬機快照和備份
OpenStack中對虛擬機的快照其實是生成一個完整的鏡像,保存在glance服務中,並且可以利用這個快照鏡像生成新的虛擬機,與原本的虛擬機並沒有什么關系。而比較主流的快照實現應該是有快照鏈的,且包含內存快照和磁盤快照。
OpenStack中的備份其實跟快照沒啥區別,調用的都是同一個生成鏡像的接口,更多的備份是cinder對磁盤的備份,沒有對整個虛擬機進行備份的接口。
4 使用ceph實現OpenStack虛擬機快照功能
(1)首先是配置OpenStack的存儲環境是Ceph存儲,因為我們要借助ceph的一些特性來實現快照
(2)從上面我們可以知道做快照,主要是對磁盤做快照和對內存數據進行保存,如果是ceph環境,那么OpenStack虛擬機的根磁盤和磁盤在ceph下就是一個塊設備,比如根磁盤一般就是保存在vms池中,其路徑是vms/<instance_id>_disk,而磁盤一般就是保存在volumes池中,其路徑是volumes/volume-<volume_id>;對於塊設備,ceph可以使用rbd命令來對塊設備做快照,比如我們對虛擬機根磁盤做快照:
rbd snap create vms/<instance_id>_disk@<snapshot_name>
snapshot_name是快照名
回滾時則執行:
rbd snap rollback vms/<instance_id>_disk@<snapshot_name>
這其實可以理解為是塊設備的內部快照方式
(3)對於內存數據,我們可以使用libvirt的save接口將內存狀態數據保存到一個文件中,為了保存到塊設備中,我們可以這樣做:
<1>新建一個塊設備(這里假設在snapshots池中創建1G大小的名為test的塊設備):
rbd create --size 1024 snapshos/test
<2>將塊設備map到物理主機中
rbd map snapshos/test
/dev/rbd0
可以看到會輸出一個磁盤設備符,使用lsblk命令則能看到該設備
<3>格式化該設備並掛載到某個目錄下
mkfs.xfs /dev/rbd0 mkdir test_dir mount /dev/rbd0 test_dir
然后我們就可以向save接口傳入test_dir目錄下的一個文件名,其會將內存狀態數據保存到該文件中,接着umount掉該塊設備:
umount -f /dev/rbd0 rbd unmap /dev/rbd0
這樣內存數據也一樣保存到塊設備中了,要使用時再掛載該塊設備訪問即可,回滾內存對應的是向libvirt的restore接口傳入該內存數據文件
注意點:
(1)libvirt的save接口調用保存完內存狀態數據后,虛擬機會關閉,這時可以執行restore接口虛擬機回滾回去
(2)回滾虛擬機時,先將該虛擬機的vm_state狀態置為ACTIVE,否則回滾會不成功
5 使用ceph實現OpenStack虛擬機增量備份功能
這里說兩個備份名詞,全量備份和增量備份。
全量備份:保存的是整個虛擬機的完整的數據
增量備份:保存的只是跟上一次相比有改動的數據
需要先做一次全量備份后,后續才能做增量備份
5.1 創建備份
這里以虛擬機的根磁盤 vms/<instance_id>_disk為例子做增量備份的操作演示:
(1)做一次全量備份
先對該塊設備做一次快照:
rbd snap create vms/<instance_id>_disk@time1
然后導出差異數據:
rbd export-diff vms/<instance_id>_disk@time1 time1_diff_file
(2)再做一次增量備份
先對該塊設備做一次快照:
rbd snap create vms/<instance_id>_disk@time2
導出time1到time2之間這段時間該磁盤的差異數據:
rbd export-diff vms/<instance_id>_disk@time2 --from-snap vms/<instance_id>_disk@time1 time2_diff_file
5.2 恢復備份
(1)如果該磁盤還存在,則直接用rbd snap rollback回滾就可以了,比如要回滾到time1這個時間點:
rbd snap rollback vms/<instance_id>_disk@time1
(2)該磁盤已經被刪掉了,要恢復該磁盤到time2的時間點:
<1>創建一個塊設備(大小跟刪除的那塊一樣大小,這里以1G為例子)
rbd create --size 1024 vms/restore_disk
<2>導入差異數據,注意這里的導入順序,先恢復到time1,再恢復到time2
rbd import-diff time1_diff_file vms/restore_disk rbd import-diff time2_diff_file vms/restore_disk
這時這塊塊設備就恢復回time2的狀態了
友情經驗點:
(1)上面的操作都是自己創建一個塊設備然后進行回滾,那怎么把這塊給到OpenStack的虛擬機使用呢?在OpenStack中添加一個磁盤是先調用api.cinder.volume_create接口創建一個卷,然后調用api.nova.instance_volume_attach將該卷連接到虛擬機中,其實我們只要將它創建的塊設備替換成我們的就可以了,比如它生成的是volumes/volume-123,我們自己回滾好的是volumes/restore_disk,則先刪掉它的塊設備,然后重命名我們的塊設備:
rbd rm volumes/volume-123 rbd rename volumes/restore_disk volumes/volume-123
(2)同理,如果我們要從備份文件中恢復到一個新的虛擬機,那么就先創建一個虛擬機,然后將它的根磁盤替換為我們恢復過數據的根磁盤,然后接着是替換硬盤,這樣我們便從備份文件中恢復到一個新的虛擬機了