伺服器架設篇 - RockyLinux 9

第二章、第一個虛擬機器的安裝與調整

KVM host 搞定之後,再來就是要建置 VM 啦!VM 安裝妥當,也需要調校效能一下喔!

最近更新時間: 2023/08/04

要讓 KVM host 順利的啟動多部 VM 還是需要其他許多額外的軟體支援才行,同時也需要可以安裝 VM 的映像檔等資料。 那麼這些資料應該放在何處比較好呢?以前 SELinux 是有規範的,不過目前似乎取消了這樣的規範,所以只要有空間,似乎都可以放置 image 與硬碟檔。這一章就讓我們來安裝第一部 VM 系統吧!未來都用這部系統來增加或減少其他任務囉!另外, 安裝完畢後,得要來重新調整硬體資源設定檔啦!讓效能更佳化比較好!

2.1、第一個虛擬機器的建置

上一章節將基礎的 KVM host 系統建置妥當之後,接下來就準備要建立第一部 VM 系統了。 我們不用原生的 qemu-kvm 指令來建立 VM,而是使用具有監督功能的 libvirtd 環境,搭配 qemu 相關週邊硬體模擬功能, 來設定與建立相關的各項虛擬硬體。建立完成之後,我們就可以透過這台虛擬機器,實際安裝另一套 Linux 囉! 也就是在 Linux 上面產生另一個邏輯上面完全獨立的 Linux 系統!

2.1.1、KVM host 上面的 libvirtd 與 virsh

從上一章節我們就知道,KVM host 應該是要安裝 libvirtd 以及 qemu 的!現在就來看看到底安裝好了沒? 此外,也來看看到底我們的核心驅動的 kvm 是給 intel 用的,還是給 AMD 用的?

  • Linux 核心 kvm 功能與參數

前面講到,KVM 其實是 Linux 核心的一部分,那麼 kvm 模組到底有沒有載入在目前的核心呢? 此外,KVM 有沒有額外的參數可以修改呢?讓我們來瞧一瞧:

# 先看看目前的核心有沒有載入 kvm 的相關模組了?
[root@cloud ~]# lsmod | grep kvm
kvm_intel             364544  0
kvm                  1056768  1 kvm_intel
irqbypass              16384  1 kvm
# 有喔!有 kvm 以及 kvm_intel 這兩個已經被載入的模組!

[root@cloud ~]# modinfo kvm
filename:       /lib/modules/5.14.0-284.18.1.el9_2.x86_64/kernel/arch/x86/kvm/kvm.ko.xz
license:        GPL
author:         Qumranet
rhelversion:    9.2
srcversion:     46781597FA45B5FA677EBFF
depends:        irqbypass
retpoline:      Y
intree:         Y
name:           kvm
vermagic:       5.14.0-284.18.1.el9_2.x86_64 SMP preempt mod_unload modversions
....
parm:           tdp_mmu:bool
parm:           mmio_caching:bool
parm:           nx_huge_pages:bool
....

[root@cloud ~]# modinfo kvm_intel
filename:       /lib/modules/5.14.0-284.18.1.el9_2.x86_64/kernel/arch/x86/kvm/kvm-intel.ko.xz
license:        GPL
author:         Qumranet
rhelversion:    9.2
srcversion:     D8E06AE51DCBA93DB578DF9
alias:          cpu:type:x86,ven*fam*mod*:feature:*0085*
depends:        kvm
retpoline:      Y
intree:         Y
name:           kvm_intel
vermagic:       5.14.0-284.18.1.el9_2.x86_64 SMP preempt mod_unload modversions
....
parm:           enable_apicv:bool
parm:           enable_ipiv:bool
parm:           nested:bool
parm:           pml:bool
....

你可以看到,目前已經有兩個 kvm 關鍵字的模組載入了,透過 modinfo 也可以看到模組的相關資訊。 在模組資訊後面的 parm 就是可以修改的模組參數!舉例來說, kvm_intel 有個 nested 的參數, 這個參數可以是啟動 (1) 也可以是關閉 (0)。如果我們需要修改這個參數,那需要處理 /etc/modprobe.d 裡面的檔案! qemu-kvm-common 有提供名為 /etc/modprobe.d/kvm.conf 的設定檔,你可以看一下:

# 修改 kvm.conf 之後,卸載再掛載 kvm_intel 看看:
[root@cloud ~]# vim /etc/modprobe.d/kvm.conf
# For Intel
options kvm_intel nested=1

[root@cloud ~]# modprobe -r kvm_intel
[root@cloud ~]# modprobe kvm_intel
[root@cloud ~]# cat /sys/module/kvm_intel/parameters/nested
Y
# 確實修訂為 Y 了!

因為鳥哥的系統上面,目前尚未執行任何 VM 啊!所以 kvm_intel 模組可以隨意抽換沒問題! 如果已經有 VM 在你的系統上面跑,那要啟動 kvm_intel 的參數,恐怕就得要重新 reboot 才行! 另外,如果想要確認設定值內容,可以到『/sys/module/模組名稱/parameters/參數名稱』查詢一下!

你可能會好奇,為什麼鳥哥特別拿 kvm_intel 這個 nested 參數做介紹? 這是因為,這個參數可以『讓你的虛擬機器裡面再開啟虛擬機器』!所以才說是巢狀 (nested) 功能啊! 相當有趣喔!鳥哥用高記憶體容量的實體機器做學生訓練的環境時,就會用到這東西了!

根據上面的資料看起來,我們目前的 Linux 核心確實已經支援 kvm 了!同時我們也知道如何調整核心參數, 接下來看一下其他的虛擬化服務與軟體吧!

  • libvirtd 服務觀察與 virsh 簡易操作

libvirtd 提供的服務相當多!目前我們大多是『有用到才啟動 libvirtd 服務』的概念,因此, 主要啟動的服務就會是『 libvirtd.socket 』才對!無論如何,都用觀察的方式來檢查一下即可:

# 看看 libvirtd 有沒有啟動!?
[root@cloud ~]# systemctl status libvirtd.socket
○ libvirtd.socket - Libvirt local socket
     Loaded: loaded (/usr/lib/systemd/system/libvirtd.socket; enabled; preset: disabled)
     Active: inactive (dead)
   Triggers: ● libvirtd.service
     Listen: /run/libvirt/libvirt-sock (Stream)
# 特別注意,觀察的是 libvirtd.socket 而不是 libvirtd.service 喔!
# 很奇怪的是,在某些時刻,服務就是啟動不了!沒關係,我們手動來重新啟動它!

[root@cloud ~]# systemctl start libvirtd.socket

基本上,就是確定有啟用就好!因為我們沒有圖形界面,因此,重點應該是在 virsh 這個指令的操作喔! 這個 virsh 就是 libvirtd 用來管理 VM 的工具軟體!你可以使用『 virsh --help 』查看一下 virsh 的用法! 他的功能多到會讓人頭暈...所以鳥哥這裡不打算仔細介紹 virsh 的詳細用法~只介紹幾個鳥哥常用的指令。 首先,讓我們來分析一下, libvirtd 如果建立一台 VM 時,它最佳的硬體設定會是怎樣?

# 檢查本機的相關虛擬化能力
[root@cloud ~]# virsh capabilities
<capabilities>

  <host>   <!--跟本機 CPU 較為相關的參數部份-->
    <uuid>f113f623-9a64-7d4e-ae37-184224474e59</uuid>
    <cpu>
      <arch>x86_64</arch>
      <model>Skylake-Client-noTSX-IBRS</model>
      <vendor>Intel</vendor>
      <microcode version='244'/>
      <signature family='6' model='165' stepping='3'/>
      <counter name='tsc' frequency='3095999000' scaling='no'/>
      <topology sockets='1' dies='1' cores='6' threads='2'/>
      <maxphysaddr mode='emulate' bits='39'/>
      <feature name='ds'/>
      ....
    </cpu>
    ....
  </host>  <!--結束跟本機 CPU 較為相關的參數部份-->

  <guest>  <!--跟用戶端 (Guest) 相關性較高的資料,這是 32 位元部份-->
    <os_type>hvm</os_type>
    <arch name='i686'>
      <wordsize>32</wordsize>
      <emulator>/usr/libexec/qemu-kvm</emulator>
      <machine maxCpus='240' deprecated='yes'>pc-i440fx-rhel7.6.0</machine>
      <machine canonical='pc-i440fx-rhel7.6.0' maxCpus='240' deprecated='yes'>pc</machine>
      ....
      <domain type='qemu'/>
      <domain type='kvm'/>
    </arch>
    ....
  </guest>

  <guest>  <!--跟用戶端 (Guest) 相關性較高的資料,這是 64 位元部份-->
    <os_type>hvm</os_type>
    <arch name='x86_64'>
      <wordsize>64</wordsize>
      <emulator>/usr/libexec/qemu-kvm</emulator>
      <machine maxCpus='240' deprecated='yes'>pc-i440fx-rhel7.6.0</machine>
      <machine canonical='pc-i440fx-rhel7.6.0' maxCpus='240' deprecated='yes'>pc</machine>
      ....
      <machine maxCpus='710'>pc-q35-rhel9.2.0</machine>
      <machine canonical='pc-q35-rhel9.2.0' maxCpus='710'>q35</machine>
      ....
      <domain type='qemu'/>
      <domain type='kvm'/>
    </arch>
    ....
  </guest>

</capabilities>

從上面的表格,我們可以看到主要的 CPU 型號、參數等,你可以將上面的參數列出在之後的硬體設定檔上面。 而在 <guest> 的項目中,我們也可以查到目前支援的虛擬機器晶片組型號!一般預設的硬體是較舊的 pc-i440fx 晶片, 但是新的應該使用 q35 比較好!你的虛擬機器有沒有支援相關的晶片,可以在這裡看出來喔!

# 檢查支援的 q35 晶片組,內部硬體模擬為何
[root@cloud ~]# virsh domcapabilities --machine q35 --arch x86_64
<domainCapabilities>
  <path>/usr/libexec/qemu-kvm</path>   <== KVM 主程式的路徑
  <domain>kvm</domain>
  <machine>pc-q35-rhel9.2.0</machine>
  <arch>x86_64</arch>
  <vcpu max='710'/>
  <iothreads supported='yes'/>
  <os supported='yes'>
    <enum name='firmware'>
      <value>efi</value>   <==主要使用 EFI 的開機引導方式
    </enum>
    <loader supported='yes'>
      <value>/usr/share/edk2/ovmf/OVMF_CODE.secboot.fd</value>  <== EFI 引導程式放置位置
      ....
    </loader>
  </os>
  <cpu>
    <mode name='host-passthrough' supported='yes'>  <==支援直接使用本機CPU
      <enum name='hostPassthroughMigratable'>
        <value>on</value>
        <value>off</value>
      </enum>
    </mode>
    <mode name='maximum' supported='yes'>
      <enum name='maximumMigratable'>
        <value>on</value>
        <value>off</value>
      </enum>
    </mode>
    <mode name='host-model' supported='yes'>
      <model fallback='forbid'>Skylake-Client-IBRS</model>
      <vendor>Intel</vendor>
      <feature policy='require' name='ss'/>
      ....
    </mode>
    <mode name='custom' supported='yes'>  <==有支援的其他模擬的 CPU 類型
      <model usable='yes' deprecated='yes' vendor='unknown'>qemu64</model>
      <model usable='yes' deprecated='yes' vendor='unknown'>qemu32</model>
      <model usable='no' deprecated='yes' vendor='AMD'>phenom</model>
      ....
    </mode>
  </cpu>
  ....
  <devices>  <==其他支援的週邊裝置
    <disk supported='yes'>  <==針對硬碟的支援類型
      <enum name='diskDevice'>
        <value>disk</value>
        <value>cdrom</value>
        <value>floppy</value>
        <value>lun</value>
      </enum>
      <enum name='bus'>     <==針對匯流排的支援類型
        <value>fdc</value>
        <value>scsi</value>
        <value>virtio</value>
        <value>usb</value>
        <value>sata</value>
      </enum>
    </disk>
    <graphics supported='yes'> <==針對圖形顯示的支援類型
      <enum name='type'>
        <value>vnc</value>
        <value>egl-headless</value>
      </enum>
    </graphics>
    <video supported='yes'>
      <enum name='modelType'>
        <value>vga</value>
        <value>cirrus</value>
        <value>virtio</value>
        <value>none</value>
        <value>bochs</value>
        <value>ramfb</value>
      </enum>
    </video>
  </devices>
  ....
</domainCapabilities>

其實仔細檢查一下可以讓用戶端使用的模擬出來的硬體,感覺還是挺有趣的!目前虛擬化的環境中, 比較常用的是 virtio 這一個模組,在磁碟、網路、顯示卡等方面,都可以透過這個模組來支援!效能比較好! 至於圖形連線的方式,根據 Red Hat 官網建議,使用 VNC 即可,若有特殊需求,則建議使用第三方軟體來連線! 總之,透過這個檢查,我們可以知道本機的 KVM host 能力,也可以知道虛擬機器未來的可用硬體就是了! 而且透過這個觀察,建議需要注意的主要內容有:

  • 使用 q35 這個主機板晶片組
  • 上述 q35 預設使用 efi 的方式啟動硬體
  • q35 的 efi 主要 ROM 檔案在 /usr/share/edk2/ovmf/OVMF_CODE.secboot.fd
  • 使用 host-passthrough 可以直接套用本機 CPU 的效果
  • 大部分的週邊可以的話,都使用 virtio 模組較佳!
  • 顯示卡的部份,可以使用 virtio/cirrus 搭配 VNC 看看。
鳥哥比較喜歡使用 spice 這個連線機制,搭配 qxl 虛擬顯卡~不過,似乎因為是某些授權的問題, 導致 Red Hat 的虛擬化團隊取消了 spice 與 qxl 虛擬顯卡的支援了!詳情請查閱底下的連結:
實做例題:
虛擬機器用到的 host 資源當中,最重要的可能就是 CPU 與記憶體。請自行使用『 virsh sysinfo 』查詢一下自己的主機環境, 看看自己的實體機器 CPU 與記憶體相關資源參數!

2.1.2、qemu 設定網路與磁碟

雖然說虛擬機器使用的都是實體機器上面的硬體資源,但是某些元件還是得要『真實存在』才可以! 兩種硬體在實體機器上面應該是得要被看見才行!那就是硬碟與網路卡。硬碟很容易處理,硬碟就是建立一個虛擬磁碟檔案即可。 網路卡就比較特別!你必須要在實體機器上面先建立一張可以被『橋接』的網路界面,這樣虛擬機器才能透過這張橋接網卡, 實際的連接到網際網路上,這也是為啥 libvirtd 預設會給一張名為 default 的橋接界面的原因。(不過不巧的,我們之前刪除了! 刪除的原因是...鳥哥不喜歡別人控制我的設備..)。

另外,在我們這份文件中,跟 KVM 有關的資料,主要分佈在三個基礎子目錄,方便未來的查詢與管理:

  • /kvm/xml:主要放置各種 XML 規範的設定檔,包括網路、虛擬機器的設定等等
  • /kvm/iso:主要放置來自網路上的各種 ISO 映像檔,例如 9.0, 9.2 的 RockyLinux 安裝光碟檔
  • /kvm/img:虛擬磁碟的放置目錄,基本上,佔用的檔案系統容量最大!
  • 用 qemu-img 建立虛擬磁碟檔案

libvirtd 支援的虛擬磁碟包括實體磁碟、LVM 實體裝置、大型檔案等等。使用實際的裝置 (實際磁碟裝置、LVM 裝置等) 在效能上,應該是比較好的。不過在系統的移轉與便利性上面,可能就有比較大的限制。因此,使用在虛擬機器當中的磁碟, 大部分還是以虛擬磁碟檔案較常見。

那麼虛擬磁碟檔案是怎麼樣的一個存在呢?舉個例子來說,如果你需要一個 100G 的虛擬磁碟,你是不是就一定要提供一個 100G 容量大小的檔案來給虛擬機器使用?有沒有『用多少、算多少』的虛擬磁碟類型呢?基本上,常見的就是這兩種類型啦!

  • raw:預先給予固定的檔案容量,如上所述,你得要建立一個 100G 的檔案才行。
  • qcow2:一種 qemu copy on write 的虛擬磁碟檔案格式,可以指定虛擬磁碟的容量,但是該容量佔用的實際磁碟空間, 則是用多少算多少。

假設我一個虛擬磁碟裡面只丟了 5G 的容量,在 raw 格式上,還是佔用了 100G 的空間,但是在 qcow2 格式上, 就只會佔用 5G 而已!所以,用容量使用效率來說,當然是使用 qcow2 比較好啊!而在讀寫效能上,因為 raw 是保有既有容量, 所以讀寫效能最佳!然而 qcow2 的效能也逼近 raw 了!因此,強烈建議直接使用 qcow2 虛擬磁碟格式即可!

建立虛擬磁碟可以使用 qemu-img 來處理!詳細的指令用法請參考 qemu-img --help 或相關的 man page。 底下僅就建立與觀察來使用 qemu-img!

# 建立一個 30G 的虛擬磁碟,名為 demo1.img
[root@cloud ~]# qemu-img create -f qcow2 -o cluster_size=[512,1K..2M] file.img size

[root@cloud ~]# mkdir /kvm/img
[root@cloud ~]# cd /kvm/img
[root@cloud img]# qemu-img create -f qcow2 -o cluster_size=2M demo1.img 30G
Formatting 'demo1.img', fmt=qcow2 cluster_size=2097152 extended_l2=off compression_type=zlib
  size=32212254720 lazy_refcounts=off refcount_bits=16

鳥哥喜歡將區塊 (cluster_size) 設定大一些,聽說這樣會有些許的效能提昇!如果你不喜歡,可以直接省略這個參數即可。 demo1.img 就是虛擬磁碟檔案,通常副檔名習慣取 .img 就是了。至於容量當然就是數字加上單位了!例如 1T 也是可接受的。 接下來,讓我們來看看這個檔案的相關規格:

[root@cloud img]# ll -h demo1.img
-rw-r--r--. 1 root root 6.1M Aug  4 11:28 demo1.img

[root@cloud img]# file demo1.img
demo1.img: QEMU QCOW2 Image (v3), 32212254720 bytes

[root@cloud img]# qemu-img info demo1.img
image: demo1.img
file format: qcow2
virtual size: 30 GiB (32212254720 bytes)
disk size: 6 MiB
cluster_size: 2097152
Format specific information:
    compat: 1.1
    compression type: zlib
    lazy refcounts: false
    refcount bits: 16
    corrupt: false
    extended l2: false
Child node '/file':
    filename: demo1.img
    protocol type: file
    file length: 6 MiB (6291968 bytes)
    disk size: 6 MiB
    Format specific information:
        extent size hint: 1048576

使用 file 可以看一下該檔案是哪種格式的資料,然後透過 qemu-img info file.img 的方式來查看虛擬磁碟的總容量! 一目了然!虛擬磁碟容量有 30G,但是實際上只佔用了 6M 左右的實際容量而已!這就是 qcow2 虛擬磁碟的格式功能!

  • 建立具有 NAT 功能的橋接界面 templan

鳥哥不是很愛使用 qemu 的網路,因為 qemu 的網路讓 libvirtd 管理之後,由於太強大了! 接管了許多實體機器的埠口與防火牆,這讓喜歡簡單操控系統的鳥哥覺得很討厭~不過,我們尚未談到網路基礎以及防火牆, 但是目前又需要建立一個橋接網卡,這樣才能讓虛擬機器直接連線到外部去!唉~真是沒辦法!所以,只好再次建立一個橋接界面。 只是,這個橋接界面會在我們講完網路基礎後,就直接刪除喔!所以鳥哥才取名為 templan 啦!

# 建立一個名為 templan 的網路界面
[root@cloud img]# mkdir /kvm/xml
[root@cloud img]# cd /kvm/xml
[root@cloud xml]# vim templan.xml
<network>
  <name>templan</name>
  <forward mode='nat'/>
  <bridge name='templan' stp='on' delay='0'/>
  <mac address='52:54:00:00:ff:01'/>
  <ip address='192.168.10.254' netmask='255.255.255.0'>
    <dhcp>
      <range start='192.168.10.1' end='192.168.10.100'/>
    </dhcp>
  </ip>
</network>
  • name: libvirtd 管理這張網卡需要的名稱
  • forward mode='nat': 虛擬機器連上網際網路的方式用 NAT(後面章節會提到)
  • bridge name='templan': 實體機器上面會生成一個名為 templan 的網路界面
  • mac address: 實體機器上面這張網路界面的卡號
  • ip address: 這張網卡的 IP 位址參數設定
  • dhcp...range..: 主動提供自動取得網路參數的服務 (dhcp 後面會提到)

建立妥當之後,我們就可以透過 virsh 來啟動這張橋接卡了!

# virsh 管理網路的基本指令
[root@cloud xml]# virsh net-list
[root@cloud xml]# virsh net-create  file.xml  <==啟動網路設定
[root@cloud xml]# virsh net-destroy file.xml  <==終止網路設定

# 實際建立橋接網路界面,並且觀察建立後的網路參數
[root@cloud xml]# virsh net-create templan.xml
Network templan created from templan.xml

[root@cloud xml]# virsh net-list
 Name      State    Autostart   Persistent
--------------------------------------------
 templan   active   no          no

[root@cloud xml]# ip addr show
.....
4: templan: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
    link/ether 52:54:00:00:ff:01 brd ff:ff:ff:ff:ff:ff
    inet 192.168.10.254/24 brd 192.168.10.255 scope global templan
       valid_lft forever preferred_lft forever

這樣就搞定虛擬磁碟以及虛擬機器需要的橋接網路界面了!接下來,讓我們處理一下實際虛擬機器的 XML 格式的硬體設定檔!

2.1.3、虛擬機器硬體設定檔 (XML 格式)

我們可以從 virsh capabilities 以及 virsh domcapabilities 找到部份的虛擬機器裝置檔案的硬體資源配置, 但是總是不直覺~有沒有什麼方法可以讓 KVM host 直接產生一個虛擬機器的裝置 XML 設定檔呢? 可以的,透過 virt-install 這個指令來產生即可!不過,要用這個指令之前,我們得要先處理好包括硬碟、網路卡、CDROM 映像檔等等。 基本上,需要預先準備的資料大致有:

  • 經由 virsh capabilities 確認支援 q35 的虛擬機器硬體
  • 經由 virsh domcapabilities 確認支援 efi 開機方式
  • 經由 virsh domcapabilities 確認支援 host-passthrough 功能
  • 光碟映像檔放置成為: /kvm/iso/Rocky-9.0-x86_64-minimal.iso
  • 硬碟檔放置在: /kvm/img/demo1.img
  • 橋接器名稱為 templan

就開始讓我們來玩玩使用 virt-install 建立一個 XML 的虛擬機器硬體設定檔吧!

# 安裝 virt-install
[root@cloud ~]# yum -y install virt-install

# 開始使用 virt-install 規劃一個用戶端硬體資源
[root@cloud ~]# cd /kvm/xml
[root@cloud xml]# virt-install \
> --name demo1 --cpu host-passthrough,cache.mode=passthrough --vcpu 4 \
> --memory 2048 --memballoon virtio --machine q35 \
> --boot uefi,loader.type=pflash,nvram=/kvm/xml/demo1.uefi.fd,loader_secure=no \
> --controller virtio-scsi \
> --disk /kvm/img/demo1.img,cache=writeback,io=threads,device=disk,bus=virtio \
> --network network=templan,model=virtio \
> --graphics vnc,port=5911,listen=0.0.0.0,password=rocky9 \
> --cdrom /kvm/iso/Rocky-9.0-x86_64-minimal.iso --video virtio \
> --dry-run --print-xml > /kvm/xml/demo1.xml
# 詳細的參數請參考 man virt-install。上述指令執行完畢,產生 demo1.xml 檔案!

懶的打字的話,鳥哥也寫文字檔給大家下載~直接 wget 下載到你的系統上就可以了!

wget https://linux.vbird.org/linux_server/rocky9/0130vmtuning/virt-install.sh

設定檔建立妥當後,很怪! XML 裡面竟然會有兩組設定!都是從 <domain...> 開始的項目! 因此,請先編輯該檔案,讓資料只存在一份,並且確認一下設定資訊是否正確。

[root@cloud ~]# vim /kvm/xml/demo1.xml
<domain type="kvm">
  <name>demo1</name>
  <uuid>ad651202-0ff0-4214-88df-aa2fd0ce8611</uuid>
  <metadata>
    <libosinfo:libosinfo xmlns:libosinfo="http://libosinfo.org/xmlns/libvirt/domain/1.0">
      <libosinfo:os id="http://rockylinux.org/rocky/9"/>
    </libosinfo:libosinfo>
  </metadata>
  <memory>2097152</memory>
  <currentMemory>2097152</currentMemory>
  <vcpu>4</vcpu>
  <os>  <== 這一段前三行應該要修改一下喔!否則啟動會失敗!
    <type arch="x86_64" machine="q35">hvm</type>
    <loader readonly="yes" type="pflash" secure="no">/usr/share/edk2/ovmf/OVMF_CODE.secboot.fd</loader>
    <nvram>/kvm/xml/demo1.uefi.fd</nvram>
    <boot dev="cdrom"/>
    <boot dev="hd"/>
  </os>
  <features>
    <acpi/>
    <apic/>
  </features>
  <cpu mode="host-passthrough">
    <cache mode="passthrough"/>
  </cpu>
  <clock offset="utc">
    <timer name="rtc" tickpolicy="catchup"/>
    <timer name="pit" tickpolicy="delay"/>
    <timer name="hpet" present="no"/>
  </clock>
  <on_reboot>restart</on_reboot>  <== 建議增加這三行
  <on_poweroff>destroy</on_poweroff>
  <on_crash>restart</on_crash>
  <pm>
    <suspend-to-mem enabled="no"/>
    <suspend-to-disk enabled="no"/>
  </pm>
  <devices>
    <emulator>/usr/libexec/qemu-kvm</emulator>
    <disk type="file" device="disk"> <== 底下這兩個是硬碟與光碟設計
      <driver name="qemu" type="qcow2" cache="writeback" io="threads"/>
      <source file="/kvm/img/demo1.img"/>
      <target dev="vda" bus="virtio"/>
    </disk>
    <disk type="file" device="cdrom">
      <driver name="qemu" type="raw"/>
      <source file="/kvm/iso/Rocky-9.0-x86_64-minimal.iso"/>
      <target dev="sda" bus="sata"/>
      <readonly/>
    </disk>
    <controller type="virtio-scsi"/> <== 這個可以拿掉
    <controller type="usb" model="qemu-xhci" ports="15"/>
    <controller type="pci" model="pcie-root"/>
    <controller type="pci" model="pcie-root-port"/>
    <controller type="pci" model="pcie-root-port"/>
    <controller type="pci" model="pcie-root-port"/>
    <controller type="pci" model="pcie-root-port"/>
    <controller type="pci" model="pcie-root-port"/>
    <controller type="pci" model="pcie-root-port"/>
    <controller type="pci" model="pcie-root-port"/>
    <controller type="pci" model="pcie-root-port"/>
    <controller type="pci" model="pcie-root-port"/>
    <controller type="pci" model="pcie-root-port"/>
    <controller type="pci" model="pcie-root-port"/>
    <controller type="pci" model="pcie-root-port"/>
    <controller type="pci" model="pcie-root-port"/>
    <controller type="pci" model="pcie-root-port"/>
    <interface type="network">  <== 單純觀察一下網路卡界面
      <source network="templan"/>
      <mac address="52:54:00:ed:63:1f"/>
      <model type="virtio"/>
    </interface>
    <console type="pty"/>
    <channel type="unix">
      <source mode="bind"/>
      <target type="virtio" name="org.qemu.guest_agent.0"/>
    </channel>
    <input type="tablet" bus="usb"/>
    <tpm model="tpm-crb">
      <backend type="emulator"/>
    </tpm>
    <graphics type="vnc" port="5911" listen="0.0.0.0" passwd="rocky9"/> <== 顯示界面與顯示卡
    <video>
      <model type="virtio"/>
    </video>
    <memballoon model="virtio"/>
    <rng model="virtio">
      <backend model="random">/dev/urandom</backend>
    </rng>
  </devices>
  <on_reboot>destroy</on_reboot>
</domain>

懶的打字的話,鳥哥也寫文字檔給大家下載~直接 wget 下載到你的系統上就可以了!

wget https://linux.vbird.org/linux_server/rocky9/0130vmtuning/demo1.xml

上述 XML 各項功能與資料,可以參考 libvirtd 提供的 XML 設定參考:

該刪除的項目與該注意的項目如上,這樣大致就建立好 q35 的 uefi 的虛擬機器硬體配置環境!

2.1.4、虛擬機器的啟動、安裝、連線與觀察

上個小節的動作,等於是『採購一部主機』的概念,同時假裝你已經將 RockyLinux 9.x 光碟片放置到光碟機內! 另外, UEFI BIOS 的快閃記憶體,假裝放置到 /kvm/xml/demo1.uefi.fd 紀錄檔~這個 UEFI 紀錄檔會自動產生! 那現在當然就是要按下虛擬機器的『 power 』囉!如何觀察呢?

# virsh 針對虛擬機器啟動、關閉、觀察的指令
[root@cloud ~]# virsh create file.xml  <==從 xml 檔案啟動虛擬機器
[root@cloud ~]# virsh list [--all]     <==列出目前 host 上面運作的虛擬機器
[root@cloud ~]# virsh shutdown VMname  <==讓某個名為 VMname 的虛擬機器關機
[root@cloud ~]# virsh destroy VMname   <==強迫某個名為 VMname 的虛擬機器斷電
  • 使用 virt-viewer 提供的 remote-viewer 當作虛擬機器的『螢幕』

虛擬機器如果啟動了,按下 power 了!那怎麼取得虛擬機器的螢幕畫面?注意喔!底下的連線『感覺』像是在電腦主機前面操作系統喔! 而『不是遠端連線』喔!這個概念要了解。所以,你可以說,我們就是將雲裡面的虛擬機器拿到我們面前來操作! 因此,等等要介紹的 remote-viewer 就是『將虛擬機器的螢幕拿到我面前來』的意思,而不是遠端登入!

我們在虛擬機器 XML 裡面設定,預設使用 VNC 協定連線『取得螢幕』,且開在 KVM host 的 port 5911, 假設你在外部使用具有 GUI 界面的環境,那麼就能使用底下的方式作為取得螢幕的網址:

  • vnc://192.168.201.249:5911

至於 vnc 的連線軟體,很多第三方軟體可以使用!也可以使用 virt-viewer 提供的 remote-viewer 軟體來處理!這個軟體目前僅提供 Linux/Windows 使用, 相關 virt-viewer 的軟體下載可參考底下連結:

上述連結在 windows 底下可以下載『 Win x64 MSI 』檔案,如果是 Linux,直接安裝 virt-manager 軟體即可! 不過就是要注意,你的 Linux 或其他作業系統,一定要有 GUI 啊!現在,讓我們來啟動這個虛擬機器, 然後趕緊連結上吧!因為只有 60 秒鐘可以選擇安裝環境而已呢!

# 1. 在 KVM host 上面,你要先放行來自用戶端的連線
[root@cloud ~]# firewall-cmd --permanent --add-port=5911/tcp
[root@cloud ~]# firewall-cmd --reload
[root@cloud ~]# firewall-cmd --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: eno1
  sources:
  services: cockpit dhcpv6-client ssh
  ports: 5911/tcp
  protocols:
  forward: yes
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:
# 後面章節談到防火牆的時候,會重新回來介紹!現在這裡先確認有 5911 存在即可!

# 立刻啟動虛擬機器 
[root@cloud ~]# virsh create /kvm/xml/demo1.xml
Domain 'demo1' created from /kvm/xml/demo1.xml

[root@cloud ~]# netstat -tlunp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 192.168.10.254:53       0.0.0.0:*               LISTEN      6105/dnsmasq
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1194/sshd: /usr/sbi
tcp        0      0 0.0.0.0:5911            0.0.0.0:*               LISTEN      6819/qemu-kvm
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      4803/master
tcp6       0      0 :::22                   :::*                    LISTEN      1194/sshd: /usr/sbi
tcp6       0      0 ::1:25                  :::*                    LISTEN      4803/master
udp        0      0 192.168.10.254:53       0.0.0.0:*                           6105/dnsmasq
udp        0      0 0.0.0.0:67              0.0.0.0:*                           6105/dnsmasq
udp        0      0 127.0.0.1:323           0.0.0.0:*                           1115/chronyd
udp6       0      0 ::1:323                 :::*                                1115/chronyd

接下來,啟動你用戶端的 remote-viewer 軟體,並且填入上述的 vnc 網址,如下所示:

使用 VNC 連線 使用 VNC 連線
使用 VNC 連線
圖 2.1.4、透過 remote-viewer 軟體,取得虛擬機器的螢幕畫面

然後做什麼呢?沒做什麼,就是按照正常的安裝流程,一項一項安裝好你的 VM 伺服器即可。

  • 第一個虛擬機器的安裝

為了完整模擬 UEFI 的環境,因此我們使用了 q35 的虛擬機器硬體設計,所以,安裝時的磁碟分割,需要很注意! 同樣需要保留大約 200M 給 /boot/efi 會比較好!你也可以指定 100M 即可!至於其他分割, 建議只須保留根目錄即可,swap 大概只給 1G 就好!畢竟還是擔心系統記憶體不足導致的當機問題。

  • 語言同樣選擇繁體中文台灣,或者是直接選擇英文,自由選擇即可
  • 語言支持,請同樣增加另一個項目,保留繁體中文與美式英文兩者
  • 時區請選擇亞洲台北
  • 磁碟分割使用自訂,使用標準分割,建立:
    • /boot/efi 大概 200M
    • swap 1G
    • / 其他容量都給這個
  • 關閉 kdump
  • 自行設定 root 密碼與建立自己的專屬一般帳號

然後就讓系統開始自己安裝起來!安裝的過程中,我們在 KVM host 上面,可以使用底下的方式來觀察看看這個 VM 的操作情況:

  • 觀察虛擬機器的運作 (在 KVM host 上面)

使用 virsh 就可以有很多觀察的資料了:

# 看有哪些 VM 在運作
[root@cloud ~]# virsh list
 Id   Name    State
-----------------------
 2    demo1   running

# 看上面 demo1 的狀態
[root@cloud ~]# virsh dominfo demo1
Id:             2
Name:           demo1
UUID:           4e8312e9-ef32-4edc-8dc0-651d7e13a51c
OS Type:        hvm
State:          running
CPU(s):         4
CPU time:       173.7s
Max memory:     2097152 KiB
Used memory:    2097152 KiB
Persistent:     no
Autostart:      disable
Managed save:   no
Security model: selinux
Security DOI:   0
Security label: system_u:system_r:svirt_t:s0:c145,c782 (enforcing)

# 看 demo1 的記憶體使用狀態
[root@cloud ~]# virsh dommemstat demo1
actual 2097152
swap_in 0
swap_out 0
major_fault 226
minor_fault 302780
unused 1521280
available 1854924
usable 1558904
last_update 1658386440
disk_caches 188752
hugetlb_pgalloc 0
hugetlb_pgfail 0
rss 2139836
  • VM 運作過程當中,進行光碟片的抽換

安裝好 rockylinux 之後,自然是需要重新開機的。這時,最好的方法當然是去 /kvm/xml/demo1.xml 裡面, 將光碟機的磁碟檔名註解掉,這樣就不會每次開機都進入安裝畫面。如果不想要關閉這部 VM 時, 則可以透過底下的手段,將光碟退出即可!(注意,安裝完畢準備開機前,才進行光碟片移除!)

# 看看目前 demo1 所使用到的磁碟方面的裝置有哪些
[root@cloud ~]# virsh domblklist demo1
 Target   Source
-------------------------------------------------
 vda      /kvm/img/demo1.img
 sda      /kvm/iso/Rocky-9.0-x86_64-minimal.iso

# 當 VM 內的 RockyLinux 9.x 安裝完畢後,在開機過程中,將光碟 sda 抽出不用
[root@cloud ~]# virsh change-media demo1 /kvm/iso/Rocky-9.0-x86_64-minimal.iso --eject
Successfully ejected media.

[root@cloud ~]# virsh domblklist demo1
 Target   Source
------------------------------
 vda      /kvm/img/demo1.img
 sda      -

此時由於沒有光碟片的存在了,因此 VM 重新開機之後,就可以直接進入新的 rockylinux 的開機流程中囉!此外, 你最好也將 demo1.xml 內的光碟片移除!這樣下次啟動這個 VM 時,就不會使用這個光碟片開機了:

[root@cloud ~]# vim /kvm/xml/demo1.xml
    <disk type="file" device="cdrom">
      <driver name="qemu" type="raw"/>
      <source file=""/>
      <target dev="sda" bus="sata"/>
      <readonly/>
    </disk>

有時候,你的 VM 安裝完畢之後,可能重新開機會失敗...機率不高,但是就是可能會發生...這個時候, 似乎也只能將這個 VM 強制關機後在重新打開了!操作的方法有點像這樣:

[root@cloud ~]# virsh destroy demo1
Domain 'demo1' destroyed

[root@cloud ~]# virsh create /kvm/xml/demo1.xml
Domain 'demo1' created from /kvm/xml/demo1.xml

2.1.5、虛擬機器 guest OS 的後續整理

虛擬機器內的作業系統我們稱為 guest OS 就是了,這個 guest OK 可以操作的方式,除了透過 remote-viewer 直接取得『螢幕』的終端畫面之外,事實上,也可以透過 ssh 之類的遠端連線伺服器進行連線,這樣就不用使用 remote-viewer 了! 也能夠在 KVM host 上面,直接轉以 ssh 來處理即可。雖然我們可以在 host 上面使用類似 arp 的指令去找出來網卡卡號與 IP 的對應, 不過還是不太直覺~所以,還是先到 remote-viewer 去查詢到正確的 IP 位址之後,再來後續的其他處置吧!

  • 使用 remote-viewer 界面,啟動虛擬機網路

從 remote-viewer 的螢幕畫面登入虛擬機器後,變更身份成為 root,接下來,讓我們來啟動網路一下:

# 1. 先查閱一下網路卡的代號
[root@localhost ~]# ip addr show
....
2: enp1s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:ed:63:1f brd ff:ff:ff:ff:ff:ff
    inet 192.168.10.52/24 brd 192.168.10.255 scope global dynamic noprefixroute enp1s0
       valid_lft 2857sec preferred_lft 2857sec
    inet6 fe80::5054:ff:feed:631f/64 scope link noprefixroute
       valid_lft forever preferred_lft forever
# 網卡的代號為 enp1s0, 且 rockylinux 9 預設會啟動網路卡喔! 

# 2. 檢查一下網路連線的名稱為何
[root@localhost ~]# nmcli connection show
NAME    UUID                                  TYPE      DEVICE
enp1s0  0b413fa2-5192-3674-a542-323759ec20bc  ethernet  enp1s0
# 果然順利找到正確的網卡代號!

[root@localhost ~]# nmcli connection show enp1s0 | grep IP4
IP4.ADDRESS[1]:     192.168.10.52/24
IP4.GATEWAY:        192.168.10.254
IP4.ROUTE[1]:       dst = 192.168.10.0/24, nh = 0.0.0.0, mt = 100
IP4.ROUTE[2]:       dst = 0.0.0.0/0, nh = 192.168.10.254, mt = 100
IP4.DNS[1]:         192.168.10.254
# 這樣就可以看到我們這部主機的 IP 位址是 192.168.10.52 喔!

這樣就可以暫時啟動網路了!同時也能抓到虛擬機器的 IP 位址哩。

  • 在 KVM host 觀察找尋 VM 網路位址的方法

我們知道虛擬機器使用的網路,其實是依附在實體機器上面的那個 templan 界面的! 如果 VM 真的有啟動網路,那麼該網路卡『應該就會紀錄 VM 傳送來的網卡紀錄』才對! 這時,我們可以反向的,從實體機器的網卡卡號紀錄功能,找到對應的 IP 位址喔!

# 這是在『實體機器』也就是在那部 KVM host 上面,實做 arp 探索!
[root@cloud ~]# arp -n
Address             HWtype  HWaddress           Flags Mask      Iface
192.168.201.252     ether   94:57:a5:9c:df:60   C               eno1
192.168.201.254     ether   18:31:bf:45:58:f2   C               eno1
192.168.10.52       ether   52:54:00:ed:63:1f   C               templan

[root@cloud ~]# arp -n -i templan
Address             HWtype  HWaddress           Flags Mask      Iface
192.168.10.52       ether   52:54:00:ed:63:1f   C               templan

透過 arp 的網卡卡號與該網卡上面的 IP 位址對應紀錄,就可以找到用戶端的 IP 位址了。 相關的 ARP 功能,我們會在後續的章節再跟大家討論一下。現在,你大概知道一下,區域網路裡面, 每張網路卡要溝通之前,都得要知道對方網卡的卡號所在就是了。

除了使用 arp 之外,從前一章學習到的 nmap 也能夠用在這裡了!

# 在 KVM host 上面,探索 192.168.10.0/24 上面的活動中的主機
[root@cloud ~]# nmap -sP 192.168.10.0/24
Starting Nmap 7.91 ( https://nmap.org ) at 2023-08-04 13:29 CST
Nmap scan report for 192.168.10.52
Host is up (0.00017s latency).
MAC Address: 52:54:00:ED:63:1F (QEMU virtual NIC)
Nmap scan report for 192.168.10.254
Host is up.
Nmap done: 256 IP addresses (2 hosts up) scanned in 2.41 seconds

為什麼 nmap 會知道這張 192.168.10.52 的網卡是 QEMU 的虛擬網卡呢?原因是,每張網卡都會有個卡號, 該卡號的前兩個位元組 (bytes) 就是製造商的識別碼啦!就這麼單純! ^_^

  • 從 KVM host 連線到 VM 進行操縱的方法: ssh

為什麼我們要去啟動 VM 的網路,並且還得要了解 VM 的 IP 位址呢?這是因為...鳥哥不喜歡啟動太多的圖形界面! 當然啦,使用 remote-viewer 連線,網路傳輸的資料量比較大,我也不喜歡!所以,想要使用純文字的方式連線到 VM, 這樣操作起來就簡單很多!而使用純文字登入的方法,大概就使用預設的 ssh 最簡單!

我們後面還會探索 ssh 這個服務,在這裡,你先知道我們可以透過 ssh 以及 scp 進行登入或資料傳輸即可。 既然已經知道 VM 的 IP 是 192.168.10.52 了,讓我們登入一下!

# ssh 的基本語法
[root@cloud ~]# ssh username@host.name.or.ip

# 在 KVM host 登入 VM 取得控制權
[root@cloud ~]# ssh vbird@192.168.10.52
The authenticity of host '192.168.10.52 (192.168.10.52)' can't be established.
ED25519 key fingerprint is SHA256:Va9Z79fb2Kv16vT9QP46iRksvxDayLYKcMY64n3txv8.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '192.168.10.52' (ED25519) to the list of known hosts.
vbird@192.168.10.52's password:  <==這裡輸入使用者的密碼
[vbird@localhost ~]$

第一次登入到這部 VM 時,ssh 會問你『要不要紀錄這個主機的公鑰碼』,這裡一定要寫『 yes 』才行! 完整的 yes 喔!多一字、少一字都不行!哈哈哈!然後才是輸入密碼,如果密碼正確, 你的畫面帳號、主機名稱就會修改!這時,你的操作行為就都在 VM 上面,而不是在 KVM host 上面喔! 很重要!

從現在開始,要進行各項操作之前,得要注意你的所在終端機是在那一個系統內喔! 因為我們會慢慢的掌握很多很多部主機,如果一個沒有掌握好...那就真的傷腦筋了!哈哈!
  • 在虛擬機器裡面進行管理任務

事實上,一部系統安裝妥當之後,許多任務都需要進行才行!包括升級、關閉網路服務、日期時間校正、 性能大致調整等等。即使是虛擬機器,這些動作也不能忽視。現在,就讓我們一步一步慢慢處理!

# 先進行全系統更新
[root@localhost ~]# yum -y update

# 常用軟體安裝
[root@localhost ~]# yum -y install bind-utils vim-enhanced \
> bash-completion net-tools yum-utils tuned

# 網路時間校正
[root@localhost ~]# vim /etc/chrony.conf
#pool 2.pool.ntp.org iburst
server ntp.ksu.edu.tw iburst
server tock.stdtime.gov.tw iburst
server time.stdtime.gov.tw iburst
#sourcedir /run/chrony-dhcp

[root@localhost ~]# systemctl start chronyd
[root@localhost ~]# systemctl enable chronyd
[root@localhost ~]# chronyc sources
MS Name/IP address         Stratum Poll Reach LastRx Last sample
^? dns3.ksu.edu.tw               3   6     3     0  +1028us[+1028us] +/-  122ms
^? 211-22-103-157.hinet-ip.>     2   6     3     1   -190us[ -190us] +/-   22ms
^? 118-163-81-61.hinet-ip.h>     2   6     3     1   +308us[ +308us] +/-   33ms

# tuned 效能調整
[root@localhost ~]# tuned-adm profile virtual-guest

# 管理員慣用操作環境處理
[root@localhost ~]# vim ~/.vimrc
"將自動縮排、自動移動畫面的功能關閉!請自行處理!
setl noai nocin nosi inde=

# 一般帳號操作環境處理
[vbird@localhost ~]# vim ~/.vimrc  <==這裡跟管理員相同動作
[vbird@localhost ~]# vim ~/.bashrc
....
alias rm='rm -i'
alias mv='mv -i'
alias cp='cp -i'

最後進行重新開機,重新開機時,你會被 VM 系統丟出來...同時,因為我們沒有設計讓 VM 自動啟用網路, 這時再也無法直接以網路連線到 VM 系統了!請愛用 remote-viewer 連線啊!另外,如果真的沒有其他要進行的任務, 那要關閉 VM 系統時,也可以在 KVM host 上面使用 virsh 指令關機即可。

# 在 KVM host 上面關閉 VM 系統
[root@cloud ~]# virsh list
 Id   Name    State
-----------------------
 3    demo1   running

[root@cloud ~]# virsh reboot demo1
Domain 'demo1' is being rebooted

[root@cloud ~]# virsh shutdown demo1
Domain 'demo1' is being shutdown

VM 的關機可能並不會成功!因為有的 VM 系統上面可能會有圖形化界面正在操作中,該情境就不會讓 virsh 直接關閉。 因此,下達 virsh shutdown 一段時間 (大部分只需要 1 分鐘內),再次 virsh list 之後,沒看到 demo1 繼續跑, 那就是正確關閉 VM 系統了!

2.2、虛擬機器重建暨性能測試與調整

前一章節,我們知道如何在 KVM host 裡面安裝一部虛擬機器,包括虛擬機器的 XML 硬體資源設定檔、 虛擬機器的 qemu 建立的 qcow2 虛擬磁碟格式、透過 qemu 建立的虛擬機器網路橋接器,同時知道如何啟動與觀察虛擬機器, 然後才在虛擬機器裡面安裝了一套完整的 RockyLinux 系統!很贊!然後呢?

想一想,我們如何採購硬體?當然,在電腦教室裡面,相同機型的桌機來幾套,裡面的硬體配備都一樣, 這樣比較好管理,而且最好裡面的作業系統通通安裝好了!那真是太棒了!好的!那麼,我們如何透過剛剛上一小節的成果, 『複製』出一堆一模一樣的桌機呢?此外,這個虛擬機器到底好用不好用?能不能再進行效能調校呢? 就讓我們繼續看下去。

2.2.1、虛擬機器的重製:透過 backing_file 副本

想一想,如果我們將上一小節的 XML 檔案複製且稍微修改一下,然後將 qemu 映像檔複製成不同檔名, 那不就可以建立新的虛擬機器的嘛?沒錯喔!有這個想法真是很讚!不過...有沒有更快速的方法? 因為那個 demo1.img 的虛擬磁碟映像檔,其實安裝好就已經是 2G 以上了!如果還有其他資料, 這個檔案會越長越大~如果都使用複製,那會不會佔用太多容量?

沒錯!很讚,你發現重點了!如果能夠像 LVM 裡面的快照 (snapshot) 一樣,就是使用原始 LVM (original) 的資料而已, 快照只是將相同區塊的資料映射到原始碟而已!相同的東西都不會重製的!只有不同的資料才會放置到快照區而已! 那 qemu 的虛擬磁碟有這功能嘛?有的!那就是副本 (backing_file)。

  • 使用 backing_file 機制創建 overlay 新檔

在 qemu 的環境中,有一個名為 backing file 的機制,這個機制可以讓原始的虛擬磁碟 (稱為基本映像檔, base image, 也就是副本, backing file),被一個可疊加的新映像檔所利用 (overlay),這個結果很像 LVM 的 original 被快照所應用類似! 有興趣的朋友可以到文末的參考資料瞧一瞧。我們可以將 demo1.img 當作是 backing file 基礎副本檔案, 其他的 overlay 新映像檔,通通是參照 backing file 來的!

實做上倒也是很簡單!建立一個新映像檔,並指定其副本來源檔名即可!

# 在 KVM host 上面,參考正確的 backing file 建立第一個 overlay
[root@cloud ~]# ll -h /kvm/img/demo1.img
-rw-r--r--. 1 root root 2.3G Aug  4 13:47 /kvm/img/demo1.img

[root@cloud ~]# qemu-img info /kvm/img/demo1.img
image: /kvm/img/demo1.img
file format: qcow2
virtual size: 30 GiB (32212254720 bytes)
disk size: 2.26 GiB
cluster_size: 2097152
....

# 前往 /kvm/img 建立名為 test1.img 的 ovarlay 映像檔
[root@cloud ~]# cd /kvm/img
[root@cloud img]# qemu-img create -f qcow2 test1.img -F qcow2 -o backing_file=/kvm/img/demo1.img
Formatting 'test1.img', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=32212254720
  backing_file=/kvm/img/demo1.img backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16

[root@cloud img]# ll -h *.img
-rw-r--r--. 1 root root 2.3G Aug  4 13:47 demo1.img
-rw-r--r--. 1 root root 193K Aug  4 15:23 test1.img

[root@cloud img]# qemu-img info test1.img
image: test1.img
file format: qcow2
virtual size: 30 GiB (32212254720 bytes)
disk size: 196 KiB
cluster_size: 65536
backing file: /kvm/img/demo1.img
backing file format: qcow2
....

你可以看到,這個 test1.img 實際佔用的容量僅有 196K 喔!另外參照檔案為 demo1.img 喔! 只是千萬要記得,由於 xml 可能來自任何地方,因此,許多的 backing_file 可能得要使用絕對路徑才好! 無論如何,我們先建立好這顆 overlay 映像檔喔!

  • 修改 xml 硬體檔案與啟動 VM

我們這個小章節的目的是想要讓 VM 的效能好,也就是說,想要修改 xml 硬體資源設定檔啦! 但是,又擔心操作過程會讓我們原本的硬碟檔案出問題,所以,簡單的想法就是拿一個一模一樣的硬碟檔案來取代掉原本的檔案即可! 然後,就可以開始隨便測試了!因此,直接修改 demo1.xml 檔案,將硬碟檔案改掉之外, 也將光碟片檔名清空,就等於將光碟片退出了!很單純!之後就可以重新使用 vnc 登入, 啟動網路來讓我們從 KVM host 登入了!整體流程有點像這樣:

# 建立 test1.xml 檔案,並且修改完畢之後啟動虛擬機器
[root@cloud ~]# cd /kvm/xml
[root@cloud xml]# cp demo1.xml test1.xml
[root@cloud xml]# vim test1.xml
  2   <name>test1</name>
  9     <nvram>/kvm/xml/test1.uefi.fd</nvram>
 36       <source file="/kvm/img/test1.img"/>
 41       <source file=""/>
 63       <mac address="52:54:00:ed:63:aa"/>
 75     <graphics type="vnc" port="5912" listen="0.0.0.0" passwd="rocky9"/>

[root@cloud xml]# virsh create /kvm/xml/test1.xml
Domain 'test1' created from /kvm/xml/test1.xml

[root@cloud xml]# virsh domblklist test1
 Target   Source
------------------------------
 vda      /kvm/img/test1.img
 sda      -

[root@cloud xml]# netstat -tlunp | egrep 'kvm|Proto'
Proto Recv-Q Send-Q Local Address  Foreign Address  State  PID/Program name
tcp        0      0 0.0.0.0:5912   0.0.0.0:*        LISTEN 5601/qemu-kvm

懶的打字的話,鳥哥也寫文字檔給大家下載~直接 wget 下載到你的系統上就可以了!

wget https://linux.vbird.org/linux_server/rocky9/0130vmtuning/test1.xml

這次我們就不使用 VNC 連線,直接用 arp 查看 IP 之後,使用 ssh 直接連線到 test1 系統內部吧!

# 先查看一下剛剛修改的網卡卡號對應 IP 位址的情況:
[root@cloud ~]# arp -n -i templan
Address             HWtype  HWaddress           Flags Mask   Iface
192.168.10.52       ether   52:54:00:ed:63:aa   C            templan

# 看起來 IP 沒有修改!OK!那我們就直接連線到 192.168.10.52 看看:
[root@cloud ~]# ssh vbird@192.168.10.52
vbird@192.168.10.52's password:
Last login: Fri Aug  4 13:47:28 2023 from 192.168.10.254
[vbird@localhost ~]$ 

如果一切都順利正常,那麼我們就可以開始準備來測試這部虛擬機器囉!

2.2.2、簡易效能測試軟體:dd, fio, iperf3

要判斷效能有沒有改變,總是需要一些測試數據的,不是用『感覺的』。鳥哥聽過最有趣的測試, 是早期還沒有這麼多可用測試工具前,有些大公司為了需要數據佐證,因此,測試人員是拿著碼表做時間紀錄的! 這真是時代的眼淚啊...目前大部分都有可用軟體可以拿來測試結果~只是,數據方面不見得是真實的! 因為各種數據都有其適用性喔!

  • 使用 dd 測試讀寫效能

有一個最笨的方法來測試寫入效能,那就是 dd 這個指令。不過要注意的是, 因為我們有磁碟陣列,而磁碟陣列的 chunk 容量並不固定!因此可能會導致不同的寫入區塊 (block) 容量, 會有效能上的差異。無論如何,讓我們找出最佳的效能有接近理論效能即可。

dd 有個很有趣的參數,稱為 oflag=direct,這個參數可以讓寫入時,不用到記憶體的輔助! 因此,所有的資料會同步寫入到磁碟,不會先寫入記憶體。這樣的測試會比較正常!

# 在 VM 環境下,實做一個連續執行的 dd 測試!記得切換成為 root
[root@localhost ~]# vim checkdd.sh
#!/bin/bash
for block in 32 64 128 512 1024
do
   count=$(( 1024 * 500 / ${block} ))
   echo "test: ${block}k"
   dd if=/dev/zero of=./test.img bs=${block}k count=${count} oflag=direct
done

[root@localhost ~]# sh checkdd.sh
test: 32k
16000+0 records in
16000+0 records out
524288000 bytes (524 MB, 500 MiB) copied, 3.91262 s, 134 MB/s
test: 64k
8000+0 records in
8000+0 records out
524288000 bytes (524 MB, 500 MiB) copied, 3.70768 s, 141 MB/s
test: 128k
4000+0 records in
4000+0 records out
524288000 bytes (524 MB, 500 MiB) copied, 3.4443 s, 152 MB/s
test: 512k
1000+0 records in
1000+0 records out
524288000 bytes (524 MB, 500 MiB) copied, 1.00981 s, 519 MB/s
test: 1024k
500+0 records in
500+0 records out
524288000 bytes (524 MB, 500 MiB) copied, 0.109536 s, 4.8 GB/s

隨便測試一個 run,結果就顯得很不同!回想一下,我們的 XML 硬體資源檔的設定當中,關於虛擬磁碟的設計是這樣的:

    <disk type="file" device="disk">
      <driver name="qemu" type="qcow2" cache="writeback" io="threads"/>
      <source file="/kvm/img/test1.img"/>
      <target dev="vda" bus="virtio"/>
    </disk>

這個 writeback 的設定值,會讓 KVM host 切出一塊記憶體,用來快取住 VM 的磁碟讀寫!以加快速度。 只是效果如何?老實說,要看 KVM host 的本體性能了!所以,上面這個測試,基本上,比較適合 KVM host 本身的測試! 鳥哥使用了 RAID10,用了 4 顆傳統磁碟,若以每顆磁碟最大具有 200Mbyes/s 的話,最高理論速度會在 400Mbytes/s 左右。

使用了 KVM host 的記憶體在快取上面,所以在用戶端的磁碟測試,基本上都是不準的!上面只是提供一個測試參考而已。 在鳥哥的 KVM host 當中,測試的結果,最高寫入發生在 block 為 128K 到 512K 之間,大概都有 350Mbytes/s 的寫入速度,老實說, 很棒了!若要取得較為準確的數據,可能得要多跑幾次喔!然後取平均~
  • 使用 fio 執行磁碟 I/O 的測試方式:

除了使用 dd 測試連續讀寫之外,RockyLinux 有提供名為 fio 的軟體來讓我們測試磁碟讀寫喔!安裝 fio 之後, 可以透過如下的指令直接測試即可:

[root@localhost ~]# yum -y install fio

# 測試隨機寫入的方式
[root@localhost ~]# fio --name=randwrite --ioengine=libaio --iodepth=1 --rw=randwrite --bs=64k \
> --direct=1 --size=1G --numjobs=1 --runtime=240 --group_reporting
randwrite: (g=0): rw=randwrite, bs=(R) 64.0KiB-64.0KiB, (W) 64.0KiB-64.0KiB, (T) 64.0KiB-64.0KiB, 
  ioengine=libaio, iodepth=1
fio-3.27
Starting 1 process
randwrite: Laying out IO file (1 file / 1024MiB)
Jobs: 1 (f=1): [w(1)][83.3%][eta 00m:02s]
randwrite: (groupid=0, jobs=1): err= 0: pid=1109: Fri Aug  4 15:42:49 2023
  write: IOPS=1600, BW=100MiB/s (105MB/s)(1024MiB/10239msec); 0 zone resets
    slat (usec): min=5, max=191, avg= 6.48, stdev= 2.05
    clat (usec): min=30, max=8895.4k, avg=617.41, stdev=69531.25
     lat (usec): min=40, max=8895.5k, avg=624.04, stdev=69531.25
    clat percentiles (usec):
     |  1.00th=[    37],  5.00th=[    38], 10.00th=[    38], 20.00th=[    39],
     | 30.00th=[    41], 40.00th=[    43], 50.00th=[    45], 60.00th=[    53],
     | 70.00th=[    74], 80.00th=[    77], 90.00th=[    83], 95.00th=[    90],
     | 99.00th=[   122], 99.50th=[   133], 99.90th=[   184], 99.95th=[   229],
     | 99.99th=[287310]
   bw (  KiB/s): min=251520, max=1003648, per=100.00%, avg=544682.67, stdev=402544.44, samples=3
   iops        : min= 3930, max=15682, avg=8510.67, stdev=6289.76, samples=3
  lat (usec)   : 50=58.58%, 100=38.58%, 250=2.81%, 500=0.01%
  lat (msec)   : 10=0.01%, 500=0.01%, >=2000=0.01%
  cpu          : usr=0.34%, sys=1.10%, ctx=16386, majf=0, minf=14
  IO depths    : 1=100.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
     submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     issued rwts: total=0,16384,0,0 short=0,0,0,0 dropped=0,0,0,0
     latency   : target=0, window=0, percentile=100.00%, depth=1

Run status group 0 (all jobs):
  WRITE: bw=100MiB/s (105MB/s), 100MiB/s-100MiB/s (105MB/s-105MB/s), io=1024MiB (1074MB), run=10239-10239msec

Disk stats (read/write):
  vda: ios=0/14831, merge=0/0, ticks=0/18435, in_queue=18435, util=97.85%

# 測試隨機讀與寫的方式
[root@localhost ~]# fio --randrepeat=1 --ioengine=libaio --direct=1 --gtod_reduce=1 \
> --name=test --filename=random_read_write.fio --bs=64k --iodepth=64 \
> --size=512M --readwrite=randrw --rwmixread=75

跟上面 dd 的狀態一樣,由於用戶端設計了 writeback 的關係,所以讀寫速度飛快!很嚇人! 其實是假的!哈哈!所以, fio 也是比較適合用在測試 KVM host 上面囉。

  • 使用 iperf3 測試網路狀態

網路是雙向的,從伺服器 (server) 到用戶端 (client),或者是從用戶端到伺服器,所以,得要有 server 與 client 才行!目前我們有一部實體 KVM host,以及一部虛擬 VM 系統,剛剛好有兩部呢!

網路效能測試,可以使用 iperf3 這個慣用的軟體!不論 server/client 都要裝上這個軟體! RockyLinux 預設就有支援這個 iperf3,所以直接安裝即可。安裝完畢之後,在 server 端執行監聽功能, 在用戶端則執行下載或上傳兩者任何一個動作即可。只是要注意,Server 仍需要放行防火牆規則! 否則仍然會擋住 client 的連線要求喔!

# Server 端:先安裝,開放防火牆,然後監聽一個 5201 的埠口:
[root@cloud ~]# yum -y install iperf3

[root@cloud ~]# firewall-cmd --add-port=5201/tcp --zone=libvirt

[root@cloud ~]# iperf3 -s &
[root@cloud ~]# netstat -tlunp | egrep 'Proto|iperf'
Proto Recv-Q Send-Q Local Address  Foreign Address  State   PID/Program name
tcp6       0      0 :::5201        :::*             LISTEN  5913/iperf3

這時 server 會啟動一個 port 5201 等待來自 client 的檢測。要注意的是,因為這次的連線僅止於測試,所以, 我就沒有將防火牆規則寫入到設定檔當中!下次 KVM host 重新開機後,這條防火牆規則就會消失喔! 然後開始在 client 端進行測試!

# Client 端:安裝好 iperf3 之後,先嘗試下載處理,測試流量
[root@localhost ~]# yum -y install iperf3

[root@localhost ~]# iperf3 -c 192.168.10.254 -p 5201 -t 10 -i 5 -R
Connecting to host 192.168.10.254, port 5201
Reverse mode, remote host 192.168.10.254 is sending
[  5] local 192.168.10.52 port 52216 connected to 192.168.10.254 port 5201
[ ID] Interval           Transfer     Bitrate
[  5]   0.00-5.00   sec  51.9 GBytes  89.1 Gbits/sec
[  5]   5.00-10.00  sec  51.5 GBytes  88.4 Gbits/sec
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate         Retr
[  5]   0.00-10.04  sec   103 GBytes  88.4 Gbits/sec    0             sender
[  5]   0.00-10.00  sec   103 GBytes  88.8 Gbits/sec                  receiver

[root@localhost ~]# iperf3 -c 192.168.10.254 -p 5201 -t 10 -i 5
Connecting to host 192.168.10.254, port 5201
[  5] local 192.168.10.52 port 42186 connected to 192.168.10.254 port 5201
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd
[  5]   0.00-5.00   sec  29.5 GBytes  50.7 Gbits/sec    0   2.41 MBytes
[  5]   5.00-10.00  sec  29.6 GBytes  50.9 Gbits/sec    0   2.41 MBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate         Retr
[  5]   0.00-10.00  sec  59.2 GBytes  50.8 Gbits/sec    0             sender
[  5]   0.00-10.04  sec  59.2 GBytes  50.6 Gbits/sec                  receiver

用戶端相關的選項與參數功能如下:

  • -c Server_IP:使用 client 模式,連線到 Server 去;
  • -t 10:僅偵測 10 秒鐘
  • -i 5:每 5 秒鐘報告一次傳輸的資訊

當然啦,還是那句話,因為我們的連線系統也都是在一部主機的內部虛擬環境, 所以,很多速度感覺上都是不可思議的!哈哈哈!這裡只是讓大家了解一下如何測試而已,數據方面可能不是太準確! 沒關係!未來你有很多機會可以用到實體機器,或者是分別位於不同實體機器內的虛擬機器, 那就有可能會用到這些測試工具囉!

2.2.3、虛擬機器效能調整

就跟實體機器一樣,虛擬機器也是有部份資料可以調整的!舉例來說,最重要的就是 cpu 的對應了! 我們未來會使用超多 VM 在一部 KVM host 上面。以目前鳥哥的系統為例,我的 i5 第 10 代,雖然說是 6 核 12 緒, 老實說,運算核心也才 6 個而已。目前一個 VM 給予 4 個核心,如果未來有超過 4 個 VM 時,可能會用到 16 個核心! 那也超過 6 個實體核心太多了!如果 4 個 VM 都是全速運算某些資料,那我原本的 KVM host 可能就沒有足夠的資源了! KVM host 如果出問題,那整體的系統就會非常怪異!因此,為了避免系統的損毀, 我們可能還是得要針對某些資源給予 VM 限制一下,比較保險一點。

  • CPU 資源限制

為了擔心讓 VM 搞到原始的 KVM host 出問題,所以,保留 1~2 個完整的實體核心給 KVM host,讓所有的 VM 只使用固定的核心,那不就可以使得系統更加穩定了!沒錯!就是這樣。但是,怎麼知道哪個執行緒是共用實體 CPU 核心呢? 簡單的說,你可以直接看 /proc/cpuinfo 或者是查詢 virsh 的輸出結果喔!

# 這是在 KVM host 上面進行的查詢喔!
[root@cloud ~]# virsh capabilities | grep siblings
            <cpu id='0' socket_id='0' die_id='0' core_id='0' siblings='0,6'/>
            <cpu id='1' socket_id='0' die_id='0' core_id='1' siblings='1,7'/>
            <cpu id='2' socket_id='0' die_id='0' core_id='2' siblings='2,8'/>
            <cpu id='3' socket_id='0' die_id='0' core_id='3' siblings='3,9'/>
            <cpu id='4' socket_id='0' die_id='0' core_id='4' siblings='4,10'/>
            <cpu id='5' socket_id='0' die_id='0' core_id='5' siblings='5,11'/>
            <cpu id='6' socket_id='0' die_id='0' core_id='0' siblings='0,6'/>
            <cpu id='7' socket_id='0' die_id='0' core_id='1' siblings='1,7'/>
            <cpu id='8' socket_id='0' die_id='0' core_id='2' siblings='2,8'/>
            <cpu id='9' socket_id='0' die_id='0' core_id='3' siblings='3,9'/>
            <cpu id='10' socket_id='0' die_id='0' core_id='4' siblings='4,10'/>
            <cpu id='11' socket_id='0' die_id='0' core_id='5' siblings='5,11'/>
# cpu id 是 CPU 執行緒編號,而 core_id 則是 CPU 實體核心編號!

[root@cloud ~]# cat /proc/cpuinfo | egrep '^processor|^core id'
processor       : 0
core id         : 0
processor       : 1
core id         : 1
processor       : 2
core id         : 2
processor       : 3
core id         : 3
processor       : 4
core id         : 4
processor       : 5
core id         : 5
processor       : 6
core id         : 0
processor       : 7
core id         : 1
processor       : 8
core id         : 2
processor       : 9
core id         : 3
processor       : 10
core id         : 4
processor       : 11
core id         : 5
# processor 是 CPU 執行緒編號,而 core id 則是 CPU 實體核心編號!

從上面這幾個指令,就可以看到,在鳥哥的這個 KVM host 系統中,CPU 號碼從 0 到 11 號,以 6 個切開,0, 6 為共用同一個實體運算核心, 1, 7 共用一個這樣。如果我想要讓所有的 VM 系統使用編號 1~5 號的實體核心,保留 0 號實體核心給原生系統使用的話, 那麼你的 XML 應該要修改成這樣:

# 讓 CPU 僅使用 1~5 號,第 0 號保留給系統使用,不要讓虛擬機器使用
[root@cloud ~]# vim /kvm/xml/demo1.xml
  <vcpu>4</vcpu>
  <vcpu placement='static' cpuset='1-5,7-11'>4</vcpu>

如此一來,編號 0 與 6 的 CPU 就不會被 VM 利用了!無論 VM 的 CPU 怎麼忙,都會有一個實體核心保留給 KVM host 喔!

  • 節省頻寬的方式:視訊壓縮

因為我們用的畢竟是 remote-viewer 的連線協定,預設的情況下,傳輸的過程當中,視訊是沒有壓縮的!對於單一連線來說,基本上,問題不大! 但是如果你的網際網路連線速度較慢,那麼可能將你的視訊資料壓縮再傳送出去,會節省比較多頻寬喔!

[root@cloud ~]# vim /kvm/xml/demo1.xml
    <graphics type="vnc" port="5911" listen="0.0.0.0" passwd="rocky9"/>
      <image compression='auto_glz' />
      <jpeg compression='auto' />
      <zlib compression='auto' />
      <playback compression='on' />
      <streaming mode='filter' />
    </graphics>

大概調整成這樣就好,同樣的,請將你的 test1.xml 也調整如上的內容, 接下來,請完整關閉 VM 之後,再次啟動。為何需要完整的關機再啟動呢?這是因為修改 XML 相當於『重新處理硬體』的意思, 所以,你得要完整關機,再次啟用時,才會使用新的 XML 檔案的內容!之後查查看是否可以看到底下的相關資訊:

# 在 KVM host 上面,看看 test1 是否真不使用 0, 6 號實體核心
[root@cloud ~]# virsh shutdown test1
[root@cloud ~]# virsh create /kvm/xml/test1.xml
[root@cloud ~]# virsh vcpuinfo test1
VCPU:           0
CPU:            1
State:          running
CPU time:       9.0s
CPU Affinity:   -yyyyy-yyyyy

VCPU:           1
CPU:            11
State:          running
CPU time:       1.5s
CPU Affinity:   -yyyyy-yyyyy

VCPU:           2
CPU:            3
State:          running
CPU time:       1.3s
CPU Affinity:   -yyyyy-yyyyy

VCPU:           3
CPU:            2
State:          running
CPU time:       1.5s
CPU Affinity:   -yyyyy-yyyyy

這就是 CPU 被定位好的證明囉!

參考資料

修改歷史:
  • 2022/05/15:母機器安裝妥當之後,處理一下 VM 的安裝與調校!這終於搞定!
  • 2022/07/21:更改成為 RockyLinux9 的版本。這個版本的 VM 環境,竟然已經不支援 spice 了!還好,之前有寫得很詳細!不然,還真的會卡住...
  • 2023/08/04:因為已經有 9.2 版本,許多的設定檔內容會改變,所以重新處理!
2022/05/15以來統計人數
計數器
其他連結
環境工程模式篇
鳥園討論區
鳥哥舊站

今日 人數統計
昨日 人數統計
本月 人數統計
上月 人數統計