Libvirt 是一組軟體的匯集,提供了管理虛擬機和其它虛擬化功能(如:存儲和網絡接口等)的便利途徑。這些軟體包括:一個長期穩定的 C 語言 API、一個守護進程(libvirtd)和一個命令行工具(virsh)。Libvirt 的主要目標是提供一個單一途徑以管理多種不同虛擬化方案以及虛擬化主機,包括:KVM/QEMU,Xen,LXC,OpenVZ 或 VirtualBox hypervisors (詳見這裡)。
Libvirt 的一些主要功能如下:
- VM management(虛擬機管理):各種虛擬機生命周期的操作,如:啟動、停止、暫停、保存、恢復和遷移等;多種不同類型設備的熱插拔操作,包括磁碟、網絡接口、內存、CPU等。
- Remote machine support(支持遠程連接):Libvirt 的所有功能都可以在運行著 libvirt 守護進程的機器上執行,包括遠程機器。可以使用最簡便且無需額外配置的 SSH 協議,也可以使用受支持的多種網絡連接方式。
- Storage management(存儲管理):任何運行 libvirt 守護進程的主機都可以用於管理多種類型的存儲:創建多種類型的文件鏡像(qcow2,vmdk,raw,...),掛載 NFS 共享,枚舉現有 LVM 卷組,創建新的 LVM 卷組和邏輯卷,對裸磁碟設備分區,掛載 iSCSI 共享,以及更多......
- Network interface management(網絡接口管理):任何運行 libvirt 守護進程的主機都可以用於管理物理的和邏輯的網絡接口,枚舉現有接口,配置(和創建)接口、橋接、VLAN、埠綁定。
- Virtual NAT and Route based networking(虛擬 NAT 和基於路由的網絡):任何運行 libvirt 守護進程的主機都可以管理和創建虛擬網絡。Libvirt 虛擬網絡使用防火牆規則實現一個路由器,為虛擬機提供到主機網絡的透明訪問。
安裝
基於守護進程/客戶端的架構的 libvirt 只需要安裝在需要要實現虛擬化的機器上。注意,伺服器和客戶端可以是相同的物理機器。
服務端
安裝 libvirt包 以及至少一個虛擬運行環境(hypervisor):
- libvirt 的 KVM/QEMU 驅動是 libvirt 的首選驅動,如果 KVM 功能已啟用,則支持全虛擬化和硬體加速的客戶機。詳見 QEMU。
- 其他受支持的虛擬運行環境包括 LXC、VirtualBox 和 Xen。請參見它們各自的安裝說明。有關
libvirtd
的安裝備註:
對於網絡連接,需要安裝這些包:
- dnsmasq包 用於默認的 NAT/DHCP 網絡
- openbsd-netcat包 用於 SSH 遠程管理
其他可選依賴項可能提供所需或擴展功能,例如 dmidecode包 用於支持 DMI 系統信息。建議在閱讀 libvirt包 的 pacman 輸出後,將所需組件作為依賴項安裝。
libvirt
5.1.0 和 firewalld 0.7.0 開始,不再需要將防火牆後端改為 iptables。libvirt
現在會在 firewalld 中自動創建名為 'libvirt' 的區域,並在該區域管理其所需的網絡規則。詳見 Firewall and network filtering in libvirt.客戶端
客戶端是用於管理和訪問虛擬機的用戶界面。
- virsh — 用於管理和配置域(虛擬機)的命令行程序。
- Boxes — 簡單的 GNOME 3 程序,可以訪問遠程虛擬系統。是 gnome-extra包組的一部分。
- Libvirt Sandbox — 應用程式沙箱工具包。
- Virt Viewer — 簡單的遠程顯示客戶端。
- Virt-manager — 用於圖形化使用 libvirt 管理 KVM,Xen 或是 LXC。
- Cockpit — 基於網頁的系統管理工具,可通過插件管理虛擬機。
兼容 libvirt 的軟體列表見這裡.
配置
Libvirt 可通過兩種模式管理 QEMU 虛擬機:system(系統模式)和 session(會話模式)[1][2]:
-
system URI 連接到以 root 身份運行的 libvirtd daemon(該進程在系統啟動時加載)。使用 'system' 模式創建和運行的虛擬機默認以 root 身份啟動,除非另行配置(例如通過
/etc/libvirt/qemu.conf
)。 - session URI 會以當前本地用戶身份啟動 libvirtd 實例,所有虛擬機均以該用戶權限運行。
模式對比分析:
- 僅 'system' 模式支持虛擬機隨宿主機啟動自動運行,且 root 權限的 libvirtd 實例擁有通過 bridge 或虛擬網絡配置完整網絡連接的權限。
qemu:///system
通常是 virt-manager 等工具的默認選項。-
qemu:///session
存在顯著缺陷:由於 libvirtd 實例權限不足,僅支持 qemu 的 usermode networking(用戶模式網絡),該模式存在隱性限制,因此不建議使用(詳見qemu 網絡配置)。
-
qemu:///session
的優勢在於權限簡化:用戶可直接在 $HOME 存儲磁碟鏡像、串行 PTY 設備歸屬用戶自身等。
對於系統 級別的管理任務(如:全局配置和鏡像卷位置),libvirt 要求至少要設置授權和啟動守護進程。
對於用戶會話 級別的管理任務,守護進程的安裝和設置不是 必須的。授權總是僅限本地,前台程序將啟動一個 libvirtd 守護進程的本地實例。
設置授權
來自 libvirt:連接授權:
- Libvirt 守護進程允許管理員分別為客戶端連接的每個網絡 socket 選擇不同授權機制。這主要是通過 libvirt 守護進程的主配置文件
/etc/libvirt/libvirtd.conf
來實現的。每個 libvirt socket 可以有獨立的授權機制配置。目前的可選項有none
、polkit
和sasl
。
Using libvirt group
把用戶加到 libvirt
user group 用戶組是確保該用戶可以訪問libvirt daemon的最簡單方法。
默認情況下,libvirt
組的成員對 RW 守護程序套接字具有免密訪問權限。
使用 polkit
Because libvirt包 pulls polkit包 as a dependency during installation, polkit is used as the default value for the unix_sock_auth
parameter (source). File-based permissions remain nevertheless available.
polkit
認證工作正常,應該重啟一次系統。libvirt 守護進程在 polkit 策略配置文件(/usr/share/polkit-1/actions/org.libvirt.unix.policy
)中提供了兩種 polkit 操作:
-
org.libvirt.unix.manage
面向完全的管理訪問(讀寫模式後台 socket),以及 -
org.libvirt.unix.monitor
面向僅監視察看訪問(只讀 socket)。
默認的面向讀寫模式後台 socket 的策略需要認證為管理員。這點類似於 sudo 認證,但它並不要求客戶應用最終以 root 身份運行。默認策略下也仍然允許任何應用連接到只讀 socket。
Arch Linux 默認 wheel
組的所有用戶都是管理員身份:定義於 /etc/polkit-1/rules.d/50-default.rules
(參閱:Polkit#管理員身份認證)。所以如果用戶是 wheel
組的成員,就不必新建組和規則文件:只要連接到了讀寫模式 socket(例如通過 virt-manager包)就會被提示輸入該用戶的口令。
pkttyagent
,它可能因工作不正常而導致各種問題。你可能想要修改授權以讀寫模式訪問 socket 的組。例如,你想授權 mykvm
組,可創建下面的文件:
/etc/polkit-1/rules.d/50-libvirt.rules
/* Allow users in mykvm group to manage the libvirt daemon without authentication */ polkit.addRule(function(action, subject) { if (action.id == "org.libvirt.unix.manage" && subject.isInGroup("mykvm")) { return polkit.Result.YES; } });
然後添加自己到 mykvm
組並重新登錄。可以將 mykvm 替換為你想要的任意組,只需確保該組存在,且用戶是該組的成員(詳情可參考用戶和用戶組)。
修改組之後不要忘記重新登錄才能生效。
基於文件的權限授權
為了給 libvirt 組用戶定義基於文件的權限以管理虛擬機,取消下列行的注釋:
/etc/libvirt/libvirtd.conf
#unix_sock_group = "libvirt" #unix_sock_ro_perms = "0777" # set to 0770 to deny non-group libvirt users #unix_sock_rw_perms = "0770" #auth_unix_ro = "none" #auth_unix_rw = "none"
有些資料提到可以通過改變某些特定 libvirt 目錄的權限以簡化管理。需要記住的是:包更新時,這些變更會丟失。如要修改這些系統目錄的權限,需要 root 用戶權限。
守護進程
libvirtd.service
和 virtlogd.service
這兩個服務單元都要啟動。可以把 libvirtd.service
設置為啟用,這時系統將同時啟用 virtlogd.service
和 virtlockd.socket
兩個服務單元,因此後二者不必再設置為啟用。
另一種方案是僅 啟動/啟用 libvirtd.socket
與 virtlogd.socket
,以實現按需 socket 激活。
非加密的 TCP/IP sockets
編輯 /etc/libvirt/libvirtd.conf
:
/etc/libvirt/libvirtd.conf
listen_tls = 0 listen_tcp = 1 auth_tcp="none"
同時需要編輯 /etc/conf.d/libvirtd
以在監聽模式下啟動服務:
/etc/conf.d/libvirtd
LIBVIRTD_ARGS="--listen"
用主機名訪問虛擬機
在非隔離的、橋接的網絡中從宿主機訪問客戶機,可以通過啟用 libvirt包 提供的 libvirt
和/或 libvirt_guest
NSS 模塊來實現。For the comparison of the two modules and technical details, see libvirt documentation.
在 nsswitch.conf(5) 中添加需要的模塊:
/etc/nsswitch.conf
hosts: files libvirt libvirt_guest dns myhostname
ping
和 ssh
這類命令使用虛擬機主機名可以正常工作,但 host
和 nslookup
這類命令可能會失敗或產生非預期結果,因後者依賴 DNS 。應改用 getent hosts <vm-hostname>
命令。測試
測試 libvirt 在系統級工作是否正常:
$ virsh -c qemu:///system
測試 libvirt 在用戶會話級工作是否正常:
$ virsh -c qemu:///session
管理
絕大部分的 libvirt 管理可以通過三個工具實現:virt-manager包(圖形界面)、virsh
和 guestfish
(它是 libguestfs包 的一部分)。
virsh
Visrsh 用於管理客戶域(虛擬機),適用於腳本及虛擬環境管理工作。受限於與虛擬化環境通信的通道,絕大部分 virsh 命令需要管理員權限。儘管如此,一些典型的管理操作如域的創建、運行等也可以像 VirtualBox 那樣以普通用戶身份執行。
Virsh 允許帶命令行選項執行。如果不帶則進入其內置的交互式終端:virsh
。交互式終端支持 tab 鍵命令補全。
從命令行執行:
$ virsh [可选项] <命令> [参数]...
在交互式終端裡運行:
virsh # <命令> [参数]...
幫助也是可用的:
$ virsh help [option*] or [group-keyword*]
存儲池
存儲池是指保存卷的位置。Libvirt 中卷的定義相當於其他系統中虛擬磁碟或虛擬機鏡像的概念。存儲池應該是一個目錄、一個網絡文件系統或一個分區(這也包括 LVM)。存儲池可以在活動與不活動之間切換,可以為其分配存儲空間。
在系統級別,默認被激活的存儲池是 /var/lib/libvirt/images/
;在用戶會話級別,virt-manager
將存儲池創建在 $XDG_DATA_HOME/images
目錄。
列出活動和不活動的存儲池的命令:
$ virsh pool-list --all
用 virsh 新建存儲池
以下示例為添加存儲池、目錄和 LVM 卷的方法:
$ virsh pool-define-as name type [source-host] [source-path] [source-dev] [source-name] [<target>] [--source-format format] $ virsh pool-define-as poolname dir - - - - /home/username/.local/libvirt/images $ virsh pool-define-as poolname fs - - /dev/vg0/images - mntpoint
上述示例僅僅定義了存儲池的信息,下面創建它:
$ virsh pool-build poolname $ virsh pool-start poolname $ virsh pool-autostart poolname
刪除它的命令:
$ virsh pool-undefine poolname
- 最佳實踐是僅把一個卷組分配給一個存儲池。
- 請為存儲池選擇一個與 LVM 卷組不同的名字。否則當存儲池被刪除時,該卷組也將被刪除。
用 virt-manager 新建存儲池
首先,連接到虛擬運行環境(例如 QEMU/KVM 的系統/用戶會話)。然後,右鍵點擊一個連接,選擇詳情;切換到存儲選項卡,點擊左下角的+,按照嚮導操作。
存儲卷
存儲池被創建之後,就可以在存儲池中創建存儲卷。如果你想新建一個域(虛擬機),那麼這一步可以跳過,因為這一步可以在創建域的過程中完成。
用 virsh 新建卷
新建卷,列出卷,變更卷大小,刪除卷:
$ virsh vol-create-as poolname volumename 10GiB --format aw|bochs|raw|qcow|qcow2|vmdk $ virsh vol-upload --pool poolname volumename volumepath $ virsh vol-list poolname $ virsh vol-resize --pool poolname volumename 12GiB $ virsh vol-delete --pool poolname volumename $ virsh vol-dumpxml --pool poolname volumename # for details.
域
虛擬機被稱作「域」。如果你想在命令行下操作,使用 virsh
列出,創建,暫停,關閉……域。virt-viewer
可以用來查看使用 virsh
啟動的域。域的創建通常以圖形化的 virt-manager
或者命令行下的 virt-install
(一個命令行工具,是 virt-install包 包的一部分)完成。
創建新域通常需要安裝媒介,例如存儲池中的 .iso
文件或是直接從光碟機安裝。
列出活動的和不活動的域:
# virsh list --all
/var/lib/libvirt/images/
中的卷可以被訪問。如果你使用 SELinux 並且在卷方面有問題,確保卷位於該目錄,或是其它存儲池的標記正常。用 virt-install 新建域
對於很詳細的域(虛擬機)配置,可以#用 virt-manager 新建域更簡單地完成。但是,基礎配置同樣可以用 virt-install
完成並且同樣順利運行。最小配置包括 --name
,--memory
,存儲(--disk
,--filesystem
或 --nodisks
)和安裝介質(通常來說是 .iso
文件或 CD)。查看 virt-install(1) 得到未列出的選項和更多的詳情。
安裝 Arch Linux(創建了 2 GiB qcow2 格式卷;用戶網絡):
$ virt-install \ --name arch-linux_testing \ --memory 1024 \ --vcpus=2,maxvcpus=4 \ --cpu host \ --cdrom $HOME/Downloads/arch-linux_install.iso \ --disk size=2,format=qcow2 \ --network user \ --virt-type kvm
Fedora testing (Xen, 非默認池,無默認控制台):
$ virt-install \ --connect xen:/// \ --name fedora-testing \ --memory 2048 \ --vcpus=2 \ --cpu=host \ --cdrom /tmp/fedora20_x84-64.iso \ --os-type=linux --os-variant=fedora20 \ --disk pool=testing,size=4 \ --network bridge=br0 \ --graphics=vnc \ --noautoconsole $ virt-viewer --connect xen:/// fedora-testing
Windows:
$ virt-install \ --name=windows7 \ --memory 2048 \ --cdrom /dev/sr0 \ --os-variant=win7 \ --disk /mnt/storage/domains/windows7.qcow2,size=20GiB \ --network network=vm-net \ --graphics spice
osinfo-query --fields=name,short-id,version os
來獲得 --os-variant
的參數,這可以幫助定製域的一些規格。然而 --memory
和 --disk
是必須被輸入的。如果需要查看這些規格,可以看看 /usr/share/libosinfo/db/oses/os.xml
(譯註:此處可能已過時)。在安裝後,推薦安裝 Spice Guest Tools,其中包括 VirtIO 驅動。Windows 的 VirtIO 網絡驅動可通過 virtio-winAUR 獲得。要使用 VirtIO,需要在虛擬機 .xml
配置中使用 <model type='virtio' />
。更多的信息可以參考 QEMU 頁面.導入現有的卷:
$ virt-install \ --name demo \ --memory 512 \ --disk /home/user/VMs/mydisk.img \ --import
用 virt-manager 新建域
首先,連接到虛擬運行環境(例如 QEMU/KVM system 或用戶 session,在連接上右擊並選擇新建,然後跟隨嚮導完成。
- 在第四步中取消選中立即分配全部虛擬磁碟空間會加快創建過程並節省實際虛擬磁碟空間占用;然而,這將導致將來花費額外的磁碟整理時間。
- 在第五步中打開高級選項並確認虛擬化類型設為 kvm(這通常是首選模式)。如果要求附加的硬體配置,選中安裝前定製選項。
管理域
啟動域:
$ virsh start domain $ virt-viewer --connect qemu:///session domain
正常關閉域;強制關閉域:
$ virsh shutdown domain $ virsh destroy domain
在 libvirtd 啟動時自動啟動域:
$ virsh autostart domain $ virsh autostart domain --disable
在宿主機關閉時自動關閉域:
- 通過使用
libvirt-guests.service
Systemd 服務,運行中的域可以在宿主機關閉時自動掛起/關閉。同時這個服務還可以讓掛起/休眠的域在宿主機啟動的時候自動恢復。可查看 libvirt-guests(8) 了解相關選項。
編輯一個域的 XML 配置:
$ virsh edit domain
參考 libvirt 維基的 XML 格式一節了解關於 XML 配置文件的信息。
網絡
這裡是有關 libvirt 網絡的的概述。
可將以下四種網絡連接到域:
- bridge——這是一個虛擬設備,它通過一個物理接口直接共享數據。使用場景為:宿主機有靜態網絡、不需與其它域連接、要占用全部進出流量,並且域運行於系統層級。網橋必須要在 libvirt 外配置,詳細操作可參考網橋。網橋創建後,需要將它指定到相應客戶機的
.xml
配置文件中。 - network——這是一個虛擬網絡,它可以與其它虛擬機共用。Libvirt 提供多種虛擬網絡模式,例如 NAT(Network address translation,網絡地址轉換)模式,路由模式和隔離模式。使用場景為:宿主機有動態網絡(例如:NetworkManager)或使用無線網絡。
- macvtap——直接連接到宿主機的一個物理網絡接口。相較橋接更加簡單,代價是宿主機無法通過該接口與域通信。Libvirt 可以很方便地配置該類網絡。
- user——本地網絡,僅用於用戶會話。
絕大多數用戶都可以通過 virsh
的各種可選項創建具有各種功能的網絡,一般來說通過 GUI 程序(像 virt-manager
之類)更方便,也可以按 #用 virt-install 新建域所述實現。
- libvirt 通過 dnsmasq包 處理 DHCP 和 DNS 請求,為每個虛擬網絡創建一個實例。它也會為特定的路由添加 iptables 規則並啟用
ip_forward
內核參數。這也意味著宿主機上無需預先運行 dnsmasq(並可能干擾到 libvirt 的 dnsmasq 實例)。 - 如果無法啟動默認網絡,請確保已安裝 iptables-nft包 和 dnsmasq包,並在 重啟
libvirtd.service
前先 啟動/啟用iptables.service
。
如果你用了 iptables包 而不是 nftables包, 那麼有必要在配置文件/etc/libvirt/network.conf
中相應地指定它。
示例:
- default: #firewall_backend = "nftables"
firewall_backend = "iptables"
通過以下命令獲取虛擬機的 IP(假設它連接到 default
網絡並通過 DHCP 獲取 IP):
$ virsh net-dhcp-leases default
如果 VM 上運行有 qemu-guest-agent
:
$ virsh domifaddr --source agent $vm
將 $vm
替換為實際的虛擬機名稱(或域 ID)。
管理並修改網絡
修改網絡前建議先閱讀 libvirt 維基的用於虛擬網絡的基本命令行用法一節。另外也建議通過 libvirt 網絡維基了解用法。
IPv6
當通過任何配置工具試圖添加 IPv6 地址時,你可能會遇到這樣的錯誤:
Check the host setup: enabling IPv6 forwarding with RA routes without accept_ra set to 2 is likely to cause routes loss. Interfaces to look at: eth0
要修復這個問題,運行如下命令(將 eth0
改為你的物理接口的名稱),並重新啟動系統。
# sysctl net.ipv6.conf.eth0.accept_ra=2
Macvtap
要創建 macvtap 網絡,先創建該文件:
macvtap.xml
<network> <name>macvtap-net</name> <forward mode='bridge'> <interface dev='eth0'/> </forward> </network>
然後定義並啟用網絡:
$ virsh net-define macvtap.xml $ virsh net-autostart macvtap-net $ virsh net-start macvtap-net
現在已創建好 macvtap-net
網絡並已持久化,它通過 eth0
橋接到外部網絡。
nftables 防火牆
當使用 NAT 類型網絡配合簡單的限制性 nftables 防火牆(例如默認配置)時,可能需要允許以下流量:
虛擬網絡接口(默認配置在此丟棄數據包)的轉發流量
來自虛擬網絡接口的 DNS/DHCP 請求(供 DHCP 客戶端與宿主機通信)
以 virbr0
作為 libvirt 橋接接口的簡化配置示例:
/etc/nftables.conf
# ... table inet filter { chain input { type filter hook input priority filter policy drop # ... iifname virbr0 udp dport {53, 67} accept comment "allow VM dhcp/dns requests to host" # ... } chain forward { type filter hook forward priority filter policy drop iifname virbr0 accept oifname virbr0 accept } }
快照
快照保存某一時刻域的磁碟、內存和設備狀態以供將來使用。快照有很多用處,例如在進行可能的破壞性操作時保存一份乾淨的域狀態。快照使用唯一名稱進行標識。
快照保存在卷之中,卷必須為 qcow2 或 raw 格式。快照使用增量存儲,所以並不會占用很多空間。
創建快照
Once a snapshot is taken it is saved as a new block device and the original snapshot is taken offline. Snapshots can be chosen from and also merged into another (even without shutting down the domain).
Print a running domain's volumes (running domains can be printed with virsh list
):
# virsh domblklist domain
Target Source ------------------------------------------------ vda /vms/domain.img
To see a volume's physical properties:
# qemu-img info /vms/domain.img
image: /vms/domain.img file format: qcow2 virtual size: 50G (53687091200 bytes) disk size: 2.1G cluster_size: 65536
Create a disk-only snapshot (the option --atomic
will prevent the volume from being modified if snapshot creation fails):
# virsh snapshot-create-as domain snapshot1 --disk-only --atomic
List snapshots:
# virsh snapshot-list domain
Name Creation Time State ------------------------------------------------------------ snapshot1 2012-10-21 17:12:57 -0700 disk-snapshot
One can then copy the original image with cp --sparse=true
or rsync -S
and then merge the original back into snapshot:
# virsh blockpull --domain domain --path /vms/domain.snapshot1
domain.snapshot1
becomes a new volume. After this is done the original volume (domain.img
and snapshot metadata can be deleted. The virsh blockcommit
would work opposite to blockpull
but it seems to be currently under development (including snapshot-revert feature
, scheduled to be released sometime next year.
其它管理操作
連接到非默認的虛擬運行環境:
$ virsh --connect xen:/// virsh # uri xen:///
通過 SSH 連接到 QEMU 虛擬運行環境,並且以相同方式登錄:
$ virsh --connect qemu+ssh://username@host/system $ LIBVIRT_DEBUG=1 virsh --connect qemu+ssh://username@host/system
通過 SSH 連接到一個圖形控制台:
$ virt-viewer --connect qemu+ssh://username@host/system domain $ virt-manager --connect qemu+ssh://username@host/system domain
連接到 VirtualBox(libvirt 對 VirtualBox 的支持尚不穩定,可能會導致 libvirtd 崩潰):
$ virsh --connect vbox:///system
網絡配置:
$ virsh -c qemu:///system net-list --all $ virsh -c qemu:///system net-dumpxml default
Hooks
鉤子 (Hooks) 是指在啟動和運行 libvirt 守護進程時,由不同事件觸發的腳本。 它們可以用來執行啟動訪客機所需的準備命令,例如設置網絡或預留內存。
libvirt 提供以下類型的鉤子:
- daemon - 觸發時機:啟動、關閉、重新加載
- qemu - 觸發時機:準備、啟動、已啟動、已停止、釋放、遷移、恢復、重新連接、附加
- lxc - 觸發時機:準備、啟動、已啟動、已停止、釋放、重新連接
- libxl - 觸發時機:準備、啟動、已啟動、已停止、釋放、遷移、重新連接
- network - 觸發時機:啟動、已啟動、已停止、埠創建、更新、埠刪除
有關每個鉤子和觸發器的詳細信息,請參見 libvirt 文檔。
新建一個 hook
鉤子由位於 /etc/libvirt/hooks
的腳本表示。如果該文件夾不存在,則需要創建它。
每個鉤子由該文件夾中同名的腳本(例如 /etc/libvirt/hooks/qemu
)或子文件夾(例如 /etc/libvirt/hooks/qemu.d/
)表示。後者可以包含不同的腳本,這些腳本在觸發點都會運行。腳本像其他任何腳本一樣運行,因此需要以要使用的命令解釋器的聲明開頭(例如 #!/bin/bash
)並可由 libvirt 用戶執行。
每當碰到觸發點時,腳本就會運行。例如,daemon 腳本在系統的啟動/停止周期中至少運行兩次,一次在啟動時,一次在關閉時。要僅在給定點運行命令,必須在腳本中實現條件。為此,libvirt 傳遞可用於識別當前觸發條件的參數。
根據 libvirt 文檔,這些參數定義如下:
- 參數 1:操作涉及的對象的名稱
- 參數 2:正在執行的操作的名稱
- 參數 3:如果要命名子操作則使用
- 參數 4:如有需要,則為額外參數 如果其中一個參數不適用,則傳遞一個連字符。
qemu
hook 需操作 virtqemud
)。示例
To run an command every time you start an qemu guest, before any resources are allocated, you can use the qemu hook. At this point, libvirt runs the hooks like this: /etc/libvirt/hooks/qemu <guest_name> prepare begin -
The script for this could like this:
/etc/libvirt/hooks/qemu
#!/bin/bash guest_name="$1" libvirt_task="$2" if [ "$libvirt_task" = "prepare" ]; then <run some important code here> fi
If the guest is stopped, the same script would be run, but this time the daemon would start the command like this: /etc/libvirt/hooks/qemu <guest_name> stopped end -
宿主機與虛擬機間共享數據
Virtio-FS
The description here will use hugepages to enable the usage of shared folders. Sharing files with Virtio-FS lists an overview of the supported options to enable filesharing with the guest.
First you need to enable hugepages which are used by the virtual machine:
/etc/sysctl.d/40-hugepage.conf
vm.nr_hugepages = nr_hugepages
To determine the number of hugepages needed check the size of the hugepages:
$ grep Hugepagesize /proc/meminfo
The number of hugepages is memory size of virtual machine / Hugepagesize. Add to this value some additional pages. You have to reboot after this step, so that the hugepages are allocated.
Now you have to prepare the configuration of the virtual machine:
# virsh edit name_of_virtual_machine
<domain> ... <memoryBacking> <hugepages/> </memoryBacking> ... <cpu ...> <numa> <cell memory='memory size of virtual machine' unit='KiB' memAccess='shared'/> </numa> </cpu> ... <devices> ... <filesystem type='mount' accessmode='passthrough'> <driver type='virtiofs'/> <source dir='path to source folder on host'/> <target dir='mount_tag'/> </filesystem> ... </devices> </domain>
It is necessary to add the NUMA definition so that the memory access can be declared as shared. id and cpus values for NUMA will be inserted by virsh.
It should now be possible to mount the folder in the shared machine:
# mount -t virtiofs mount_tag /mnt/mount/path
Add the following fstab entry to mount the folder automatically at boot:
/etc/fstab
... mount_tag /mnt/mount/path virtiofs rw,noatime,_netdev 0 0
9p
File system directories can be shared using the 9P protocol. Details are available in QEMU's documentation of 9psetup.
Configure the virtual machine as follows:
<domain> ... <devices> ... <filesystem type="mount" accessmode="mapped"> <target dir="mount_tag"/> </filesystem> </devices> </domain>
Boot the guest and mount the shared directory from it using:
# mount -t 9p -o trans=virtio,version=9p2000.L mount_tag /path/to/mount_point/on/guest
See https://docs.kernel.org/filesystems/9p.html for more mount options.
To mount it at boot, add it to the guest's fstab:
/etc/fstab
... mount_tag /path/to/mount_point/on/guest 9p trans=virtio,version=9p2000.L 0 0
The module for the 9p transport (i.e. 9pnet_virtio
for trans=virtio
) will not be automatically loaded, so mounting the file system from /etc/fstab
will fail and you will encounter an error like 9pnet: Could not find request transport: virtio
. The solution is to preload the module during boot:
/etc/modules-load.d/9pnet_virtio.conf
9pnet_virtio
Samba / SMB
An other easy way to share data between guest and host is to use the smb protocol. While performance and latency may not be as good as in the other described ways, its sufficient for simple tasks like transfering simple files like images or documents from and to the guest.
The smb server can be set up directly on either the host, or the guest, for example using Samba, eliminating the need for a dedicated file server. Windows guests have the ability to create smb shares included right after installation (Microsoft Supportpage).
One possible way to access the share under linux (either from the host, or from the guest, depending, where you have installed your server) is to create an entry in your fstab. The samba包 package is required.
/etc/fstab
#Accessing a samba share on my vm from the host //my_vm/my_share /home/archuser/my_vm cifs _netdev,noauto,nofail,user,credentials=/home/archuser/.config/my_vm.key,gid=1000,uid=984 0 0
_netdev,noauto,nofail
ensures that the share is only mounted when needed without causing issues if the vm is not booted. user,credentials=/home/user/.config/my_vm.key,gid=1000,uid=984
gives you the ability to mount the share on the fly while first accessing it, without needing a password.
UEFI 支持
Libvirt 可以通過 QEMU 和 OVMF 來支持 UEFI 虛擬機。
安裝 edk2-ovmf包。
重啟 libvirtd
。
你現在就可以創建 UEFI 虛擬機了。通過 virt-manager包 創建一台虛擬機,在到達新建虛擬機嚮導的最後一頁時,進行如下操作:
- 勾選在安裝前自定義配置,之後點擊完成。
- 在概況屏幕, 將固件改為:
- UEFI x86_64: /usr/share/edk2/x64/OVMF_CODE.4m.fd:無安全啟動支持的 x64 UEFI,
- UEFI x86_64: /usr/share/edk2/x64/OVMF_CODE.secboot.4m.fd:帶安全啟動支持的 x64 UEFI(無預置證書)。
- 點擊應用。
- 點擊開始安裝
參考 Fedora:Using UEFI with QEMU 獲得更多信息。
小技巧
在虛擬機中使用整個物理磁碟設備
若宿主機存在包含其他作業系統(如 Windows)的獨立物理磁碟,可將其配置為虛擬機中的虛擬磁碟進行啟動。由於採用原始磁碟訪問,虛擬機內磁碟性能接近原生。
Windows 虛擬機啟動前提條件
在嘗試啟動前,必須在該磁碟的 Windows 系統中安裝 virtio 驅動:
- Windows 7:使用版本 0.1.173-4。新版 virtio 中的部分驅動可通過設備管理器手動安裝
- Windows 10:支持最新 virtio 版本
配置 Windows 磁碟接口驅動
若啟動時遭遇 0x0000007B
藍屏錯誤,表示 Windows 在早期啟動階段無法訪問磁碟(因相關接口驅動未加載或設置為手動啟動)。需 修改註冊表強制驅動隨系統啟動:
- 打開註冊表編輯器,定位至
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
- 對以下鍵值(如存在)執行操作:
aliide, amdide, atapi, cmdide, iastor, iastorV, intelide, LSI_SAS, msahci, pciide, viaide
- 將每個鍵中的 Start 值改為 0
- 若使用 PCIe NVMe 磁碟,需同樣啟用對應驅動
獲取磁碟唯一標識路徑
執行 ls /dev/disk/by-id/
查看磁碟 ID(例如,得到 ata-TS512GMTS930L_C199211383
則 /dev/disk/by-id/ata-TS512GMTS930L_C199211383
為磁碟唯一標識)
通過 QEMU CLI 添加磁碟
在 QEMU 命令行中添加參數:-drive file=/dev/disk/by-id/ata-TS512GMTS930L_C199211383,format=raw,media=disk
(替換 file=
後的路徑為實際磁碟路徑)
通過 libvirt XML 添加磁碟
在 QEMU 命令行中添加參數:
$ virsh edit vmname
... <disk type="block" device="disk"> <driver name="qemu" type="raw" cache="none" io="native"/> <source dev="/dev/disk/by-id/ata-TS512GMTS930L_C199211383"/> <target dev="sda" bus="sata"/> <address type="drive" controller="0" bus="0" target="0" unit="0"/> </disk> ...
替換 file=
後的路徑為實際磁碟路徑
通過 virt-manager 添加磁碟
- 新建虛擬機:選擇 "導入現有磁碟",粘貼磁碟唯一路徑
- 已有虛擬機:添加設備 → 存儲 → 選擇/創建自定義存儲 → 粘貼磁碟路徑
Python 連接代碼
libvirt-python包 在 /usr/lib/python3.x/site-packages/libvirt.py
提供了一個 Python API。
常用例子在 /usr/share/doc/libvirt-python-your_libvirt_version/examples/
給出。
一個使用 qemu-desktop包 和 openssh包 的例子(非官方):
#! /usr/bin/env python3 import socket import sys import libvirt conn = libvirt.open("qemu+ssh://xxx/system") print("Trying to find node on xxx") domains = conn.listDomainsID() for domainID in domains: domConnect = conn.lookupByID(domainID) if domConnect.name() == 'xxx-node': print("Found shared node on xxx with ID {}".format(domainID)) domServ = domConnect break
先進格式化 4K 原生硬碟
To turn a disk into an Advanced Format 4Kn disk, both its physical and logical sector size needs to be set to 4 KiB. For virtio-blk and virtio-scsi this can be done by setting the logical_block_size
and physical_block_size
options with the <blockio> element. For example:
# virsh edit name_of_virtual_machine
<domain> ... <devices> ... <disk type='file' device='disk'> .. <blockio logical_block_size='4096' physical_block_size='4096'/> </disk> ... </devices> </domain>
控制 QEMU
Libvirt is capable of passing on QEMU command line arguments to the underlying QEMU instance running the VM. This functionality is highly useful when libvirt does not provide QEMU features (yet). For examples, see the entire Intel GVT-g article.
modify VM XML schema for QEMU
This serves to enable QEMU-specific elements. Change
$ virsh edit vmname
<domain type='kvm'>
to
$ virsh edit vmname
<domain xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0' type='kvm'>
QEMU 命令行參數
In libvirt, QEMU command line arguments separated by whitespaces need to be provided separately.
The correct location to insert them is at the end of the <domain>
element, i. e. right above the closing </domain>
tag.
-display gtk,gl=es,zoom-to-fit=off
Becomes
$ virsh edit vmname
... </devices> <qemu:commandline> <qemu:arg value="-display"/> <qemu:arg value="gtk,gl=es,zoom-to-fit=off"/> </qemu:commandline> </domain>
排障
系統實例下的 PulseAudio
PulseAudio 守護進程通常在你的普通用戶下運行,並且只接受來自相同用戶的連接。然而 libvirt 默認使用 root 運行 QEMU。為了讓 QEMU 在普通用戶下運行,編輯 /etc/libvirt/qemu.conf
並將 user
設置為你的用戶名。
user = "dave"
你同樣需要告訴 QEMU 使用 PulseAudio 後端並識別要連接的伺服器。使用 virsh edit
將如下內容添加到你的域配置中:
<audio id="1" type="pulseaudio" serverName="/run/user/1000/pulse/native"> <input latency="20000"/> <output latency="20000"/> </audio>
1000
是你的用戶 ID,如有必要可修改。
可省略延遲參數(單位:微秒),但使用默認值可能導致音頻出現 crackling(爆音)。
Hypervisor CPU 使用率過高
virt-manager 生成的默認虛擬機配置可能導致 QEMU 進程占用較高 CPU(10-20%)。若以無界面模式運行虛擬機,建議移除非必要設備
Virtual machine cannot be un-paused on virt-manager
If you are using a disk image format such as qcow2 which has a specified virtual capacity, but only stores what is needed, then you need to have space on the host partition for the image to grow. If you see I/O related errors when attempting to start the VM, it's possible that the host partition holding the virtual disk image is full. You can run df -h
on the host to verify how much free space is available.
If this is the case, see System maintenance#Clean the filesystem for ways to free up space.
Redirect USB Device is greyed out in virt-manager
If the Redirect USB Device menu item is greyed out, check that the following hardware is configured for the VM:
- A USB Controller.
- One or more USB Redirectors.
Error starting domain: Requested operation is not valid
When you try to open a virtual machine this error may pop up. This is because when you try to open a existing virtual machine libvirt tries to search for the default network which is not available. To make it available you have to autostart your network interface so that whenever your restart your computer your network interface is always active. See libvirt networking page.
Look at the name of your network interface with the following command:
# virsh net-list --all
To autostart your network interface:
# virsh net-autostart name_of_the_network
To start your network interface:
# virsh net-start name_of_the_network
Virt Manager Error 'Virt Manager doesn't have search permissions'
Ensure the folder containing your virtual machine files and installation ISO are owned by the libvirt-qemu
group
$ sudo chown -R $USER:libvirt-qemu /path/to/virtual/machine
啟動域時錯誤:請求的操作無效:網絡 'default' 未激活
若默認網絡因故處於未激活狀態,所有配置使用該網絡的虛擬機將無法啟動。初步解決措施可嘗試通過 virsh 手動啟動網絡:
# virsh net-start default
若問題仍未解決,請參考 網絡故障排查指南