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版本
[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編譯之后,默認會提供這個工具,如下關系鏈
/----- <- [centos1.qcow2] <- [centos1_A.qcow2] <- [centos1_B.qcow2] [(centosbase)]| \----- <- [centos2.qcow2] <- [centos2_A.qcow2] <- [centos2_B.qcow2]
#使用模板鏡像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,所以這兩個磁盤只有幾百個字節大小,只有新的文件才會被寫入此磁盤
#查看鏡像信息,包括虛擬磁盤大小,實際占用空間,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,創建過程中可以觀察磁盤大小的變化
#查看虛擬機信息 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虛擬機,查看當前所使用磁盤
virsh start centos2 virsh domblklist centos2 Target Source ------------------------------------------------ vda /data_lij/vhosts/centos2.qcow2 hdc -
#可以看到,當前所使用磁盤為centos2.qcow2,之前說過,外置磁盤快照創建時,會保存正在使用磁盤作為backing file(此磁盤不再接受新數據,只保存快照前的數據),並創建一個新的磁盤作為overlays以等待寫入新數據
2.創建外置快照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 ... #所使用磁盤已經更新到新創建的磁盤
3.查看新磁盤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
4.查看所有外置快照
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.查看當前使用磁盤
virsh domblklist centos2
vda /data_lij/vhosts/centos2_sn4.qcow2
#虛擬機centos2使用的是最后一個快照的磁盤(稱作active),重點要理解的是快照之間是相互依賴的(上一個依賴下一個),每一部分都保存有數據,所有的快照合起來保存虛擬機的全部數據
6.查看虛擬機centos2的完整快照鏈(centos2_sn4.qcow2為當前使用磁盤)
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快照,下面有兩種方式
(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中
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
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
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
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
參考文章
http://itxx.sinaapp.com/blog/content/130
https://kashyapc.fedorapeople.org/virt/lc-2012/snapshots-handout.html
