Photo by Agent J on Unsplash

KubeVirt-K8S上的VM服務專案(2)-VM的儲存空間

Eddie Yen
Gemini Open Cloud 雙子星雲端
12 min readOct 13, 2022

--

在第一篇中,針對 KubeVirt 已先做過簡介、建立 KubeVirt 環境以及在上面建立第一個 VM。接下來會深入探討,KubeVirt 的一些特性及與一般 VM 在儲存、網路等不同差異之處。

KubeVirt 的儲存類型與應用

在第一篇中,大略把 KubeVirt 上的儲存空間分為永久與非永久這兩類,並且簡單說明了每一個儲存類型。在本篇,將會針對這些儲存類型做比較具體的說明以及其可能的應用之處。

K8S 支援的掛載並不等於全部都可用在 KubeVirt 上!

首先必須要提到的是,KubeVirt 的服務最終型態還是以 VM 為主,因此不能將 K8S 運行容器的概念完全套用在 KubeVirt 上。
例如,K8S 容器可以在沒有 StorageClass 的情況下,手動建立 PV 與 PVC 連接後掛載進容器內使用,以及可以使用 volume 和 volumeMount 的方式,在建立 Pod 時將主機端或遠端的路徑位置掛載使用;但 KubeVirt 並不具備這樣的功能,畢竟 VM 的儲存運行主體還是以其 image 為主,兩者之間的儲存格式即存在本質上的不同。

在第一篇中,有提到 KubeVirt 支援的儲存類型分為三類,分別為非永久性、永久性和定義性三類:
非永久性:儲存空間會在 VM 建立時一同創建,但 VM 刪除時也會一併被刪除。
永久性:儲存空間本身就存在或者 VM 建立時一同創建,當 VM 刪除時,儲存空間會被保留下來。
定義性:這類儲存空間不存放任何媒體性質的資料,而是存放設定檔、密碼等等這類資訊類的資料。可對應 K8S 本身的 configMap 及 Secret。

在一般所認知的雲端環境中,非永久性儲存通常用在給客戶短期試用、或者將原先的範本包成應用服務後提供給客戶或是自身使用,而在後者的狀況中,則是根據客戶需求,另外掛載一個永久性儲存類型的媒體當作客戶需要存放的位置,或者直接提供一個永久性儲存空間來運行系統,讓客戶的長期運行服務使用。要直接類比的話,就類似於 Openstack 建立 Instance 時,從 image 建立或者從 volume 建立的差別。而定義性儲存空間,通常是做為掛載一些設定檔進去環境內,使環境啟動時不需人工登入設定,即可直接快速設定好服務的直接做法。

非永久性儲存類型

emptyDisk:當 VM 建立時,KubeVirt 會根據建立 VM 時定義的 Disk 大小,在 Pod 內產生一個 QCOW2 image,並掛載進 VM 內為虛擬硬碟。由於是在Pod內建立的關係,當VM刪除時,Pod也會隨之刪除,該image也會被刪除。這種類型通常應用在內部安裝測試的用途居多,很少會拿來在Production Site上使用。

containerDisk:顧名思義,將 VM image 打包成 container image,然後掛載給 VM 使用,為 KubeVirt 的特色之一。

永久性儲存類型

PersistentVolumeClaim(PVC):與一般的 Pod 容器一樣,KubeVirt 所建立的 VM 也可直接使用 PVC 做為儲存空間,而存放的方式則是把 VM image 直接存放在 PVC 內,VM 建立或啟動時再掛載進 VM 內;若 PVC 內沒有 image, KubeVirt 會根據 PVC 的大小建立 image。此類型為 KubeVirt 常用的永久性儲存類型,同時也被 K8S 廣泛支援。缺點是 PVC 需要手動建立,且若要將原先的 image 放入 PVC,則需要透過一些其他手段放入。

DataVolume(DV):此類型同樣使用 PVC 為基底,差別在可直接於 VM 或 VMI 的 YAML 內定義 DV 的 image 來源。當 VM 建立時,KubeVirt 會根據提供的來源自動獲取 image、生成 PVC 並存入其中。此類型與containerDisk 一樣,適合用在大量佈建時所使用,差別只在建立的儲存空間都是永久的,另外在較新的 KubeVirt 版本中,擴增 PVC 的大小也會自動擴增 image 的大小。由於 DV 是 KubeVirt 自身的功能,需要透過其他的組件才能運作,若要使用 DV,必須要在環境上安裝 KubeVirt CDI 套件。

HostDisk:此類型不使用 PVC 等儲存空間,而是直接使用本機端的路徑檔案作為來源,類似 K8S Volume 的 HostPath 機制;若指定的路徑找不到檔案,也可以設定自動建立,並且設定要建立的大小。缺點是這目前在 KubeVirt 上還是實驗性質,必須要在 FeatureGate 啟用此功能才能使用,且不支援 Migration。

定義性儲存類型

CloudInitNoCloud/CloudInitConfigDrive:此類型為專門存放 cloud-init 的資料,並且在 VM 建立時根據該檔案的內容來初始化作業系統。Cloud-init 是雲端環境很常見的套件,用來對雲端用的 image 做初期的客製化設定,包括可設定密碼、設定 IP、安裝套件、修改主機名稱等。KubeVirt 提供了這項功能,以讓使用者可直接使用公版或是自身客製化的 Cloud image,直接在KubeVirt 上快速建立與運行。而此儲存類型的設定檔編寫,基本上與 K8S 的ConfigMap 及 cloud-init 無異。
順帶一提,NoCloud 與 ConfigDrive 之間的差異,在於是否需要連線到雲端環境的 metadata 伺服器取得初始化內容,為 cloud-init 運作上的差異。

其他KubeVirt支援的定義性儲存類型,如 ConfigMap 與 Secret 等,基本上與K8S自身是共通的,因此這邊就不再介紹。

非永久性與永久性儲存的支援程度

KubeVirt的虛擬儲存媒體

前面所提到的各類儲存類型,都是所謂的後端連接到 VM image 等實際存取來源,接著就來看看前端,也就是掛載進 VM 內變成虛擬儲存媒體時的設定。

目前 KubeVirt 支援的虛擬媒體中,有支援光碟機(cdrom)、硬碟(disk)和iSCSI(LUN),其中前兩者也是多數情境下最常使用的。在 KubeVirt 的定義中,都定義在 devices/disk 這個類別內。以下我們就用第一篇用來建立 VM的 YAML 檔案來當作範例:

在 disks 類別中,每一個虛擬儲存媒體都定義為一個陣列,定義媒體的類型、名稱及相關設定
● name:虛擬儲存媒體的名稱,只在 YAML 上定義,不會在 VM 內顯示
● cdrom/disk:定義儲存媒體為 cdrom 或是 disk。
● bus:定義這個儲存媒體在 VM 內是使用哪種虛擬硬體介面去連接,有分sata、virtio 與 scsi。沒有設定的話預設為 sata
● bootOrder:定義儲存媒體的開機順序,其數字從1開始,主要開機順序由這個參數來決定,而非媒體在 YAML 內的排列順序。須注意作為安裝系統的目標磁碟必須要設定此參數,否則部分安裝程式可能會視為該硬碟不可開機而拒絕安裝。

針對 bus 的部分,一般是使用 sata 居多,優點是相容性高,缺點是虛擬 I/O效能較差,因此做為系統碟使用的 disk 媒體,通常會建議使用 virtio 來加強效能;相反地,非 Linux 的作業系統普遍都不支援 virtio,若要讓 Windows能夠使用 virtio,必須在安裝作業系統時載入驅動程式,才可以抓到硬碟。另外,為了要讓安裝程式能夠順利開機,以及能夠載入 virtio 驅動程式給安裝程式,掛載 ISO 成虛擬光碟機時,bus 則一定要用 sata。

簡單來說,通常 bus 的建議設定如下:虛擬硬碟=virtio,虛擬光碟機=sata。

接著再來看 volume 部分。剛好可以看到三種儲存類型在 volume 上的寫法,分別為 persistentVolumeClaim、hostDisk 和 containerDisk。

與一般建立 Pod 時一樣,每一個 Volume 都有獨立的名稱,然後在 disks 區塊再去設定每一個虛擬媒體所對應的 Volume 名稱,以此進行對應掛載。

● persistentVolumeClaim 只需要設定要使用的 PVC 名稱即可,注意 PVC 須和要建立的 VMI 處在同一個 namespace 下,若要存取不同 namespace 的PVC,則可以寫成 <namespace>/<PVC名稱> 的形式,並且確保有給予其他namespace 可存取的權限

● hardDisk 的 type 可為 Disk 或 DiskOrCreate,前者是直接使用指令路徑的 image,後者則是指定路徑找不到 image 時自動建立新的 image。當需要建立新的 image 檔案時,則需要帶入 capacity 來指定要建立的 image 大小。

● containerDisk 則是只需要輸入容器 image 的名稱即可,在此範例中,則是去掛載 KubeVirt 放在 Docker Hub 上的 virtio 驅動程式 image。

在 VM 建立時,每個虛擬媒體會根據定義的 Volume 名稱,掛載對應的來源。這便是 KubeVirt 在掛載儲存媒體時所使用的方式。

專屬於 KubeVirt 所使用的 containerDisk

在前面有提到 containerDisk 的類型,亦即將 VM image 打包進容器 image 內使用。

當建立 VM 時,Pod 會啟動兩個容器,其中一個容器會去掛載指定的容器 image 進開 VM 的容器內,再把裡面的 VM image 載入進 VM 內;由於只是把容器 image 內的 VM image 放進 Pod 內運行,因此 VM 刪除時,原先存放的資料也會消失。此類型通常用在大量部署且不需要保留資料、或者是做為掛載 ISO 時很常使用。缺點是沒辦法像 Openstack 的 VM 一樣能夠透過 resize 去擴增空間。

那麼 containerDisk 與一般的容器 image 結構差在哪邊呢?先說結論,大體結構上都是一樣的,只有裡面所存放的檔案有所差異。

一般的容器 image,除了會有該 image 的元數據、layer 清單等之外,還會包含該 image 的每一個 layer 層的封裝檔及該封裝資訊。若把其中一個 layer封裝檔解開看,可以發現每一個 layer 會是一個類似 Linux 的檔案結構,並且不同的 layer 只會存放有存在差異的檔案,只有基底 layer 才會有完整的檔案結構。

將容器image的其中一個layer封裝檔解封後的模樣

對於 containerDisk 而言就相對簡單。與一般容器 image 一樣, containerDisk 也有自己的 image 元數據及封裝資訊等,但若把 layer 內的封裝檔解開後,通常情況下可以發現只會有一個名為 disk 的資料夾,並且裡面存放 VM 或是 ISO 的 image;也就是說,containerDisk 裡面存放的並非完整的檔案結構,而是單純的運行用 image。

將containerDisk的layer封裝檔解封後的模樣,並用qemu-img確認image類型

另外,KubeVirt 允許在使用 containerDisk 時,對於存放 VM/ISO image 的資料夾定義不同的名稱,只要在 YAML 內額外定義 image 的具體路徑即可。而這樣做的好處是,這允許管理者將常用的 VM/ISO image 都放進同一個containerDisk 內,透過同一個 containerDisk 來存取裡面不同的 VM/ISO image。若沒有定義,KubeVirt 預設會去讀取 /disk 路徑內的唯一 image。

由於沒辦法直接碰觸到裡面的 VM image,因此 containerDisk 類型的儲存沒辦法動態或是關機擴充 image 的大小,也就沒辦法調整主要儲存空間的容量。因此若規劃使用 containerDisk,則須事先規劃給應用或是使用者使用的預留空間,並且視需求另外使用 PVC 等來源掛載資料儲存空間。

同時,也因為上述的問題,使用 containerDisk 做為 root disk 的 VM,也無法做 Snapshot。

小結

本篇介紹了 KubeVirt 所使用的儲存類型與應用,可以發現大多數 KubeVirt 可使用的儲存類型,都是以 K8S 為基底下去運作,包括 PVC、emptyDir 等,另外包含了 containerDisk、HostDisk、以及可定義 VM 初始化內容的CloudInit 相關 Volume 類型等專讓 KubeVirt 使用的功能。儘管儲存部分與傳統 IaaS 服務的雲端環境相比,KubeVirt 還是有不小的差異與不足之處,但其已可以滿足小型或基本的使用需求。

雙子星雲端為 CNCF 會員,是 CNCF 所認證的 Kubernetes 服務提供商,在雲端技術擁有十多年以上的經驗,為台灣雲端技術早期領先者。目前為國家級 AI 雲的軟體及 Kubernetes 技術與服務提供商,更是諸多企業與單位導入容器與管理平台的最佳夥伴。

雙子星雲端已於近期推出 Kubernetes 管理平台 — Gemini Management Console,可搭配既有的產品 AI Console 與 Gemini API Gateway ,也提供企業諮詢與導入雲原生 Kubernetes、CI/CD 導入等相關技術服務,協助企業擁抱 Cloud Native,達到數位轉型的目標。

--

--