在 k8s 中使用 Kubevirt 運行管理 Windows 10 操作系統(tǒng)

更多奇技淫巧歡迎訂閱博客:https://fuckcloudnative.io
前言
最近我發(fā)現(xiàn)我的 Kubernetes 集群資源實在是太多了,有點浪費,不信你看:

既然閑置資源那么多,那我何不想辦法利用一下。怎么用,用來干什么又是一個問題,想到我手中只有 MacBook,缺少 Windows 操作系統(tǒng),那就先想辦法用 Kubernetes 創(chuàng)建個 Windows 虛擬機用用吧,畢竟很多場景只能用 Windows(比如突破某盤的限速、Xshell 一把梭連接所有服務(wù)器)。于是我將目光轉(zhuǎn)向了 Kubevirt。
Kubevirt 是 Red Hat 開源的以容器方式運行虛擬機的項目,通過 CRD 的方式來管理虛擬機實例,它的所有概念都和一般的 Kubernetes 容器應(yīng)用差不多,不需要增加學習成本,對于咱玩爛了容器的 YAML 工程師來說沒有任何壓力,我們可以直接用它來創(chuàng)建虛擬機啊。
1. Kubevirt 架構(gòu)設(shè)計
Kubevirt 主要實現(xiàn)了下面幾種資源,以實現(xiàn)對虛擬機的管理:
VirtualMachineInstance(VMI): 類似于 kubernetes Pod,是管理虛擬機的最小資源。一個VirtualMachineInstance對象即表示一臺正在運行的虛擬機實例,包含一個虛擬機所需要的各種配置。VirtualMachine(VM): 為群集內(nèi)的VirtualMachineInstance提供管理功能,例如開機/關(guān)機/重啟虛擬機,確保虛擬機實例的啟動狀態(tài),與虛擬機實例是 1:1 的關(guān)系,類似與spec.replica為 1 的 StatefulSet。VirtualMachineInstanceReplicaSet: 類似ReplicaSet,可以啟動指定數(shù)量的VirtualMachineInstance,并且保證指定數(shù)量的VirtualMachineInstance運行,可以配置 HPA。
Kubevirt 的整體架構(gòu)如圖:

virt-api : 負責提供一些 KubeVirt 特有的 api,像是 console, vnc, startvm, stopvm等。virt-controller : 管理和監(jiān)控 VMI 對象及其關(guān)聯(lián)的 Pod,對其狀態(tài)進行更新。 virt-hander : 以 DaemonSet 運行在每一個節(jié)點上,監(jiān)聽 VMI 的狀態(tài)向上匯報,管理 VMI 的生命周期。 virt-launcher : 以 Pod 方式運行,每個 VMI Object 都會對應(yīng)一個 virt-launcher Pod,容器內(nèi)有單獨的 libvirtd,用于啟動和管理虛擬機。
如果你嫌上面的架構(gòu)圖太繁瑣,這里還有一個簡化版:

這個圖里的 Agent 其實就是 virt-hander。
2. 磁盤和卷
虛擬機鏡像(磁盤)是啟動虛擬機必不可少的部分,KubeVirt 中提供多種方式的虛擬機磁盤,虛擬機鏡像(磁盤)使用方式非常靈活。這里列出幾種比較常用的:
PersistentVolumeClaim : 使用 PVC 做為后端存儲,適用于數(shù)據(jù)持久化,即在虛擬機重啟或者重建后數(shù)據(jù)依舊存在。使用的 PV 類型可以是 block 和 filesystem,使用 filesystem 時,會使用 PVC 上的 /disk.img,格式為 RAW 格式的文件作為硬盤。block 模式時,使用 block volume 直接作為原始塊設(shè)備提供給虛擬機。 ephemeral : 基于后端存儲在本地做一個寫時復制(COW)鏡像層,所有的寫入都在本地存儲的鏡像中,VM 實例停止時寫入層就被刪除,后端存儲上的鏡像不變化。 containerDisk : 基于 scratch 構(gòu)建的一個 docker image,鏡像中包含虛擬機啟動所需要的虛擬機鏡像,可以將該 docker image push 到 registry,使用時從 registry 拉取鏡像,直接使用 containerDisk 作為 VMI 磁盤,數(shù)據(jù)是無法持久化的。 hostDisk : 使用節(jié)點上的磁盤鏡像,類似于 hostpath,也可以在初始化時創(chuàng)建空的鏡像。dataVolume : 提供在虛擬機啟動流程中自動將虛擬機磁盤導入 pvc 的功能,在不使用 DataVolume 的情況下,用戶必須先準備帶有磁盤映像的 pvc,然后再將其分配給 VM 或 VMI。dataVolume 拉取鏡像的來源可以時 http,對象存儲,另一塊 PVC 等。
3. 準備工作
在安裝 Kubevirt 之前,需要做一些準備工作。先安裝 libvrt 和 qemu 軟件包:
#?Ubuntu
$?apt?install?-y?qemu-kvm?libvirt-bin?bridge-utils?virt-manager
#?CentOS
$?yum?install?-y?qemu-kvm?libvirt?virt-install?bridge-utils
查看節(jié)點是否支持 kvm 硬件輔助虛擬化
$?virt-host-validate?qemu
??QEMU:?Checking?for?hardware?virtualization?????????????????????????????????:?PASS
??QEMU:?Checking?if?device?/dev/kvm?exists???????????????????????????????????:?PASS
??QEMU:?Checking?if?device?/dev/kvm?is?accessible????????????????????????????:?PASS
??QEMU:?Checking?if?device?/dev/vhost-net?exists?????????????????????????????:?PASS
??QEMU:?Checking?if?device?/dev/net/tun?exists???????????????????????????????:?PASS
??QEMU:?Checking?for?cgroup?'memory'?controller?support??????????????????????:?PASS
??QEMU:?Checking?for?cgroup?'memory'?controller?mount-point??????????????????:?PASS
??QEMU:?Checking?for?cgroup?'cpu'?controller?support?????????????????????????:?PASS
??QEMU:?Checking?for?cgroup?'cpu'?controller?mount-point?????????????????????:?PASS
??QEMU:?Checking?for?cgroup?'cpuacct'?controller?support?????????????????????:?PASS
??QEMU:?Checking?for?cgroup?'cpuacct'?controller?mount-point?????????????????:?PASS
??QEMU:?Checking?for?cgroup?'cpuset'?controller?support??????????????????????:?PASS
??QEMU:?Checking?for?cgroup?'cpuset'?controller?mount-point??????????????????:?PASS
??QEMU:?Checking?for?cgroup?'devices'?controller?support?????????????????????:?PASS
??QEMU:?Checking?for?cgroup?'devices'?controller?mount-point?????????????????:?PASS
??QEMU:?Checking?for?cgroup?'blkio'?controller?support???????????????????????:?PASS
??QEMU:?Checking?for?cgroup?'blkio'?controller?mount-point???????????????????:?PASS
??QEMU:?Checking?for?device?assignment?IOMMU?support?????????????????????????:?PASS
??QEMU:?Checking?if?IOMMU?is?enabled?by?kernel???????????????????????????????:?PASS
如果不支持,則先生成讓 Kubevirt 使用軟件虛擬化的配置:
$?kubectl?create?namespace?kubevirt
$?kubectl?create?configmap?-n?kubevirt?kubevirt-config?\
????--from-literal?debug.useEmulation=true
4. 安裝 Kubevirt
部署最新版本的 Kubevirt
$?export?VERSION=$(curl?-s?https://api.github.com/repos/kubevirt/kubevirt/releases?|?grep?tag_name?|?grep?-v?--?'-rc'?|?head?-1?|?awk?-F':?'?'{print?$2}'?|?sed?'s/,//'?|?xargs)
$?kubectl?apply?-f?https://github.com/kubevirt/kubevirt/releases/download/${VERSION}/kubevirt-operator.yaml
$?kubectl?apply?-f?https://github.com/kubevirt/kubevirt/releases/download/${VERSION}/kubevirt-cr.yaml
查看部署結(jié)果:
$?kubectl?-n?kubevirt?get?pod
NAME???????????????????????????????READY???STATUS????RESTARTS???AGE
virt-api-64999f7bf5-n9kcl??????????1/1?????Running???0??????????6d
virt-api-64999f7bf5-st5qv??????????1/1?????Running???0??????????6d8h
virt-controller-8696ccdf44-v5wnq???1/1?????Running???0??????????6d
virt-controller-8696ccdf44-vjvsw???1/1?????Running???0??????????6d8h
virt-handler-85rdn?????????????????1/1?????Running???3??????????7d19h
virt-handler-bpgzp?????????????????1/1?????Running???21?????????7d19h
virt-handler-d55c7?????????????????1/1?????Running???1??????????7d19h
virt-operator-78fbcdfdf4-sf5dv?????1/1?????Running???0??????????6d8h
virt-operator-78fbcdfdf4-zf9qr?????1/1?????Running???0??????????6d
部署 CDI
Containerized Data Importer(CDI)項目提供了用于使 PVC 作為 KubeVirt VM 磁盤的功能。建議同時部署 CDI:
$?export?VERSION=$(curl?-s?https://github.com/kubevirt/containerized-data-importer/releases/latest?|?grep?-o?"v[0-9]\.[0-9]*\.[0-9]*")
$?kubectl?create?-f?https://github.com/kubevirt/containerized-data-importer/releases/download/$VERSION/cdi-operator.yaml
$?kubectl?create?-f?https://github.com/kubevirt/containerized-data-importer/releases/download/$VERSION/cdi-cr.yaml
5. 客戶端準備
Kubevirt 提供了一個命令行工具 virtctl,可以直接下載:
$?export?VERSION=$(curl?-s?https://api.github.com/repos/kubevirt/kubevirt/releases?|?grep?tag_name?|?grep?-v?--?'-rc'?|?head?-1?|?awk?-F':?'?'{print?$2}'?|?sed?'s/,//'?|?xargs)
$?curl?-L?-o?/usr/local/bin/virtctl?https://github.com/kubevirt/kubevirt/releases/download/$VERSION/virtctl-$VERSION-linux-amd64
$?chmod?+x?/usr/local/bin/virtctl
也可以通過 krew 安裝為 kubectl 的插件:
$?kubectl?krew?install?virt
6. 虛擬機鏡像準備
Windows 鏡像下載
這里推薦兩個 Windows 鏡像下載站:
① MSDN I Tell You[1]。該網(wǎng)站提供的鏈接是 ed2k 格式,需要通過特殊下載工具進行下載,比如百度網(wǎng)盤離線下載、迅雷、eMule 等,其中百度網(wǎng)盤離線下載最好使,但下載限速又是個大問題,開了超級會員的當我沒說。

② TechBench by WZT[2]。該網(wǎng)站提供的是直鏈下載方式,可以用任意下載工具進行下載,比上面的網(wǎng)站方便多了,不過資源沒有上面的網(wǎng)站豐富。

我推薦通過第二個網(wǎng)站來下載 Windows 鏡像。
上傳鏡像
KubeVirt 可以使用 PVC 作為后端磁盤,使用 filesystem 類型的 PVC 時,默認使用的時 /disk.img 這個鏡像,用戶可以將鏡像上傳到 PVC,在創(chuàng)建 VMI 時使用此 PVC。使用這種方式需要注意下面幾點:
一個 PVC 只允許存在一個鏡像,只允許一個 VMI 使用,要創(chuàng)建多個 VMI,需要上傳多次 /disk.img的格式必須是 RAW 格式
CDI 提供了使用使用 PVC 作為虛擬機磁盤的方案,在虛擬機啟動前通過下面方式填充 PVC:
通過 URL 導入虛擬機鏡像到 PVC,URL 可以是 http 鏈接,s3 鏈接 Clone 一個已經(jīng)存在的 PVC 通過 container registry 導入虛擬機磁盤到 PVC,需要結(jié)合 ContainerDisk使用通過客戶端上傳本地鏡像到 PVC
通過命令行 virtctl,結(jié)合 CDI 項目,可以上傳本地鏡像到 PVC 上,支持的鏡像格式有:
.img .qcow2 .iso 壓縮為 .tar,.gz,.xz 格式的上述鏡像
我們的目標是安裝 Windows 10 虛擬機,所以需要將上面下載好的 Windows 鏡像上傳到 PVC:
$?virtctl?image-upload?\
??--image-path='Win10_20H2_Chinese(Simplified)_x64.iso'?\
??--pvc-name=iso-win10?\
??--pvc-size=7G?\
??--uploadproxy-url=https://?\
??--insecure?\
??--wait-secs=240
PersistentVolumeClaim?default/iso-win10?created
Waiting?for?PVC?iso-win10?upload?pod?to?be?ready...
Pod?now?ready
Uploading?data?to?https://10.111.29.156
?5.63?GiB?/?5.63?GiB?[======================================================================================================================================================]?100.00%?27s
Uploading?data?completed?successfully,?waiting?for?processing?to?complete,?you?can?hit?ctrl-c?without?interrupting?the?progress
Processing?completed?successfully
Uploading?Win10_20H2_Chinese(Simplified)_x64.iso?completed?successfully
參數(shù)解釋:
--image-path : 操作系統(tǒng)鏡像地址 --pvc-name : 指定存儲操作系統(tǒng)鏡像的 PVC,這個 PVC 不需要提前準備好,鏡像上傳過程中會自動創(chuàng)建。 --pvc-size : PVC 大小,根據(jù)操作系統(tǒng)鏡像大小來設(shè)定,一般略大一個 G 就行。 --uploadproxy-url : cdi-uploadproxy 的 Service IP,可以通過命令 kubectl -n cdi get svc -l cdi.kubevirt.io=cdi-uploadproxy來查看。
7. 創(chuàng)建虛擬機
創(chuàng)建 Windows 虛擬機的模板文件如下:
win10.yaml
apiVersion:?kubevirt.io/v1alpha3
kind:?VirtualMachine
metadata:
??name:?win10
spec:
??running:?false
??template:
????metadata:
??????labels:
????????kubevirt.io/domain:?win10
????spec:
??????domain:
????????cpu:
??????????cores:?4
????????devices:
??????????disks:
??????????-?bootOrder:?1
????????????cdrom:
??????????????bus:?sata
????????????name:?cdromiso
??????????-?disk:
??????????????bus:?virtio
????????????name:?harddrive
??????????-?cdrom:
??????????????bus:?sata
????????????name:?virtiocontainerdisk
??????????interfaces:
??????????-?masquerade:?{}
????????????model:?e1000
????????????name:?default
????????machine:
??????????type:?q35
????????resources:
??????????requests:
????????????memory:?16G
??????networks:
??????-?name:?default
????????pod:?{}
??????volumes:
??????-?name:?cdromiso
????????persistentVolumeClaim:
??????????claimName:?iso-win10
??????-?name:?harddrive
????????hostDisk:
??????????capacity:?50Gi
??????????path:?/data/disk.img
??????????type:?DiskOrCreate
??????-?containerDisk:
??????????image:?kubevirt/virtio-container-disk
????????name:?virtiocontainerdisk
這里用到了 3 個 Volume:
cdromiso : 提供操作系統(tǒng)安裝鏡像,即上文上傳鏡像后生成的 PVC iso-win10。harddrive : 虛擬機使用的磁盤,即操作系統(tǒng)就會安裝在該磁盤上。這里選擇 hostDisk直接掛載到宿主機以提升性能,如果使用分布式存儲則體驗非常不好。containerDisk : 由于 Windows 默認無法識別 raw 格式的磁盤,所以需要安裝 virtio 驅(qū)動。containerDisk 可以將打包好 virtio 驅(qū)動的容器鏡像掛載到虛擬機中。
關(guān)于網(wǎng)絡(luò)部分,spec.template.spec.networks 定義了一個網(wǎng)絡(luò)叫 default,這里表示使用 Kubernetes 默認的 CNI。spec.template.spec.domain.devices.interfaces 選擇定義的網(wǎng)絡(luò) default,并開啟 masquerade,以使用網(wǎng)絡(luò)地址轉(zhuǎn)換 (NAT) 來通過 Linux 網(wǎng)橋?qū)⑻摂M機連接至 Pod 網(wǎng)絡(luò)后端。
使用模板文件創(chuàng)建虛擬機:
$?kubectl?apply?-f?win10.yaml
啟動虛擬機實例:
$?virtctl?start?win10
#?如果 virtctl 安裝為 kubectl 的插件,命令格式如下:
$?kubectl?virt?start?win10
查看實例運行狀態(tài):
$?kubectl?get?pod
NAME??????????????????????????????READY???STATUS????RESTARTS???AGE
virt-launcher-win10-s742j?????????2/2?????Running???0??????????15s
然后就可以通過 VNC 工具來訪問 Windows 虛擬機了。首先需要在本地安裝一個 VNC 客戶端,對于 macOS 來說,可以安裝 Tiger VNC 或者 Real VNC。我選擇安裝 Real VNC:
$?brew?cask?install?vnc-viewer
連接到 Windows 虛擬機:
$?virtctl?vnc?win10
#?如果 virtctl 安裝為 kubectl 的插件,命令格式如下:
$?kubectl?virt?vnc?win10
執(zhí)行完上面的命令后,就會打開本地的 VNC 客戶端連接到虛擬機:

下面就是安裝正常的安裝步驟往下進行,到選擇硬盤那一步的時候,你會發(fā)現(xiàn)沒有一個硬盤可供使用,這時就需要安裝 virtio 驅(qū)動了。

不過不用擔心,virtio 驅(qū)動已經(jīng)被掛載進來了,直接點擊加載驅(qū)動程序就可以安裝驅(qū)動了:


安裝好驅(qū)動后,硬盤就能正確顯示了:

下面就可以繼續(xù)安裝了。

安裝成功后會自動重啟進行初始化設(shè)置,那個熟悉的“海內(nèi)存知己,天涯若比鄰”又回來了:

設(shè)置完成后,進入系統(tǒng),打開設(shè)備管理器,可以看到有幾個未配置的設(shè)備。選擇其中一個右鍵單擊,然后選擇“更新驅(qū)動程序”。

選擇“瀏覽我的電腦以查找驅(qū)動程序”。

選擇“CD 驅(qū)動器(E:)virtio-win-0.1.1”,然后點擊確定。

設(shè)備管理器將自動找到正確的驅(qū)動程序,不需要指定驅(qū)動程序的路徑。
在提示符下,單擊“安裝”。

其他的設(shè)備驅(qū)動可以復制上面的步驟一一安裝。
8. CNI 插件問題解決
如果你的 Kubernetes 集群 CNI 插件用的是 Calico,這里會遇到虛擬機無法聯(lián)網(wǎng)的問題。因為 Calico 默認禁用了容器的 ip forward 功能,而 masquerade 需要開啟這個功能才能生效。
我們只需要修改 Calico 的 ConfigMap 就可以啟用容器的 ip forward 功能了,執(zhí)行以下命令打開 configmap calico-config:
$?kubectl?-n?kube-system?edit?cm?calico-config
在 CNI 配置文件中加上以下的內(nèi)容:
"container_settings":?{
????"allow_ip_forwarding":?true
},
修改完的配置文件內(nèi)容:
??cni_network_config:?|-
????{
??????"name":?"k8s-pod-network",
??????"cniVersion":?"0.3.1",
??????"plugins":?[
????????{
??????????"type":?"calico",
??????????"log_level":?"info",
??????????"log_file_path":?"/var/log/calico/cni/cni.log",
??????????"etcd_endpoints":?"__ETCD_ENDPOINTS__",
??????????"etcd_key_file":?"__ETCD_KEY_FILE__",
??????????"etcd_cert_file":?"__ETCD_CERT_FILE__",
??????????"etcd_ca_cert_file":?"__ETCD_CA_CERT_FILE__",
??????????"mtu":?__CNI_MTU__,
??????????"ipam":?{
??????????????"type":?"calico-ipam"
??????????},
??????????"container_settings":?{
??????????????"allow_ip_forwarding":?true
??????????},
??????????"policy":?{
??????????????"type":?"k8s"
??????????},
??????????"kubernetes":?{
??????????????"kubeconfig":?"__KUBECONFIG_FILEPATH__"
??????????}
????????},
????????{
??????????"type":?"portmap",
??????????"snat":?true,
??????????"capabilities":?{"portMappings":?true}
????????},
????????{
??????????"type":?"bandwidth",
??????????"capabilities":?{"bandwidth":?true}
????????}
??????]
????}
然后重啟 calico-node 容器:
$?kubectl?-n?kube-system?delete?pod?-l?k8s-app=calico-node
8. 遠程連接
在系統(tǒng)未安裝好之前,只能用 VNC 來遠程控制,但 VNC 的體驗實在讓人難受。現(xiàn)在系統(tǒng)裝好了,就可以使用 Windows 的遠程連接協(xié)議 RDP(Remote Desktop Protocol) 了。選擇開始 >設(shè)置 >系統(tǒng)>遠程桌面,打開啟用遠程桌面就好了。
現(xiàn)在可以通過 telnet 來測試一下 RDP 端口(3389)的連通性:
$?kubectl?get?pod?-owide
NAME??????????????????????????????READY???STATUS????RESTARTS???AGE?????IP???????????????NODE????NOMINATED?NODE???READINESS?GATES
virt-launcher-win10-s742j?????????2/2?????Running???0??????????139m????100.92.235.131???k8s03??????????????
$?telnet?100.92.235.131?3389
Trying?100.92.235.131...
Connected?to?100.92.235.131.
Escape?character?is?'^]'.
如果你的本地電腦能夠直連 Pod IP 和 SVC IP,現(xiàn)在就可以直接通過 RDP 客戶端來遠程連接 Windows 了。如果你的本地電腦不能直連 Pod IP 和 SVC IP,但可以直連 Kubernetes 集群的 Node IP,可以通過 NodePort 來暴露 RDP 端口。具體操作是創(chuàng)建一個 Service,類型為 NodePort:
$?kubectl?virt?expose?vm?win10?--name?win10-rdp?--port?3389?--target-port?3389?--type?NodePort
$?kubectl?get?svc
NAME?????????????????????TYPE????????CLUSTER-IP??????EXTERNAL-IP???PORT(S)??????????AGE
kubernetes???????????????ClusterIP???10.96.0.1???????????????443/TCP??????????17d
win10-rdp????????????????NodePort????10.98.20.203????????????3389:31192/TCP???20m
然后就可以通過 Node IP 來遠程連接 Windows 了。
如果你的本地操作系統(tǒng)是 Windows 10,可以在任務(wù)欄的搜索框中,鍵入“遠程桌面連接”,然后選擇“遠程桌面連接”。在“遠程桌面連接”中,鍵入你想要連接的電腦的名稱(從步驟 1),然后選擇**“連接”**。
如果你的本地操作系統(tǒng)是 macOS,需要在 App Store 中安裝 Microsoft Remote Desktop。

安裝完之后打開應(yīng)用,選擇 Add PC:

在 PC name 一欄中輸入 NodeIP+NodePort,然后點擊 Add。

然后右擊創(chuàng)建好的配置,選擇 Connect:

輸入賬號密碼后就可以連接到 Windows 了。

全屏之后就可以獲得完美的遠程桌面體驗了,盡情玩耍吧!
嘻嘻,刺不刺激?

如果你對最后一張圖比較感興趣,可在公眾號后臺回復 百度 獲取你想要的東西。
9. 參考
在 Kubernetes 上使用 KubeVirt 管理虛擬機負載[3] kubevirt-crc-windows-tutorial[4] kubevirt user guide[5]
參考資料
MSDN I Tell You: https://msdn.itellyou.cn/
[2]TechBench by WZT: https://tb.rg-adguard.net/public.php
[3]在 Kubernetes 上使用 KubeVirt 管理虛擬機負載: http://blog.meoop.me/post/use-kubevirt-to-manage-virtualization-workloads-on-kubernetes/
[4]kubevirt-crc-windows-tutorial: https://redhat-developer-demos.github.io/kubevirt-crc-windows-tutorial/
[5]kubevirt user guide: https://kubevirt.io/user-guide/


你可能還喜歡
點擊下方圖片即可閱讀

云原生是一種信仰??

掃碼關(guān)注公眾號
后臺回復?k8s?獲取史上最方便快捷的 Kubernetes 高可用部署工具,只需一條命令,連 ssh 都不需要!


點擊?"閱讀原文"?獲取更好的閱讀體驗!
??給個「在看」,是對我最大的支持??

