原文連接:fuckcloudnative.io/posts/use-k…php
最近我發現個人 Kubernetes
集羣資源實在是太多了,有點浪費,不信你看:node
既然閒置資源那麼多,那我何不想辦法利用一下。怎麼用,用來幹什麼又是一個問題,想到我手中只有 MacBook,缺乏 Windows 操做系統,那就先想辦法用 Kubernetes 建立個 Windows 虛擬機用用吧,畢竟不少場景只能用 Windows(好比突破某盤的限速、Xshell 一把梭鏈接全部服務器)。因而我將目光轉向了 Kubevirt。linux
Kubevirt
是 Red Hat 開源的以容器方式運行虛擬機的項目,經過 CRD
的方式來管理虛擬機實例,它的全部概念都和通常的 Kubernetes 容器應用差很少,不須要增長學習成本,對於咱玩爛了容器的 YAML 工程師來講沒有任何壓力,咱們能夠直接用它來建立虛擬機啊。git
Kubevirt 主要實現了下面幾種資源,以實現對虛擬機的管理:github
VirtualMachineInstance(VMI)
: 相似於 kubernetes Pod,是管理虛擬機的最小資源。一個 VirtualMachineInstance
對象即表示一臺正在運行的虛擬機實例,包含一個虛擬機所須要的各類配置。VirtualMachine(VM)
: 爲羣集內的 VirtualMachineInstance
提供管理功能,例如開機/關機/重啓虛擬機,確保虛擬機實例的啓動狀態,與虛擬機實例是 1:1 的關係,相似與 spec.replica
爲 1 的 StatefulSet。VirtualMachineInstanceReplicaSet
: 相似 ReplicaSet
,能夠啓動指定數量的 VirtualMachineInstance
,而且保證指定數量的 VirtualMachineInstance
運行,能夠配置 HPA。Kubevirt 的總體架構如圖:docker
console, vnc, startvm, stopvm
等。libvirtd
,用於啓動和管理虛擬機。若是你嫌上面的架構圖太繁瑣,這裏還有一個簡化版:shell
這個圖裏的 Agent 其實就是 virt-handler。json
虛擬機鏡像(磁盤)是啓動虛擬機必不可少的部分,KubeVirt 中提供多種方式的虛擬機磁盤,虛擬機鏡像(磁盤)使用方式很是靈活。這裏列出幾種比較經常使用的:windows
hostpath
,也能夠在初始化時建立空的鏡像。在安裝 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
複製代碼
查看節點是否支持 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
複製代碼
$ 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
複製代碼
查看部署結果:
$ 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
複製代碼
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
複製代碼
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
複製代碼
這裏推薦兩個 Windows 鏡像下載站:
① MSDN I Tell You。該網站提供的連接是 ed2k
格式,須要經過特殊下載工具進行下載,好比百度網盤離線下載、迅雷、eMule 等,其中百度網盤離線下載最好使,但下載限速又是個大問題,開了超級會員的當我沒說。
② TechBench by WZT。該網站提供的是直鏈下載方式,能夠用任意下載工具進行下載,比上面的網站方便多了,不過資源沒有上面的網站豐富。
我推薦經過第二個網站來下載 Windows 鏡像。
KubeVirt 可使用 PVC 做爲後端磁盤,使用 filesystem
類型的 PVC 時,默認使用的時 /disk.img
這個鏡像,用戶能夠將鏡像上傳到 PVC,在建立 VMI 時使用此 PVC。使用這種方式須要注意下面幾點:
/disk.img
的格式必須是 RAW 格式CDI 提供了使用使用 PVC 做爲虛擬機磁盤的方案,在虛擬機啓動前經過下面方式填充 PVC:
ContainerDisk
使用經過命令行 virtctl
,結合 CDI 項目,能夠上傳本地鏡像到 PVC 上,支持的鏡像格式有:
咱們的目標是安裝 Windows 10 虛擬機,因此須要將上面下載好的 Windows 鏡像上傳到 PVC:
$ virtctl image-upload \
--image-path='Win10_20H2_Chinese(Simplified)_x64.iso' \
--storage-class csi-rbd-sc \
--pvc-name=iso-win10 \
--pvc-size=7G \
--uploadproxy-url=https://<cdi-uploadproxy_svc_ip> \
--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
複製代碼
參數解釋:
kubectl -n cdi get svc -l cdi.kubevirt.io=cdi-uploadproxy
來查看。Kubevirt 默認沒有開啓對 hostDisk
的支持,須要手動開啓。步驟也很簡單,只需新建個 ConfigMap,增長 hostDisk
的特性:
kubevet-config.yaml
apiVersion: v1
data:
feature-gates: LiveMigration,DataVolumes,HostDisk
kind: ConfigMap
metadata:
labels:
kubevirt.io: ""
name: kubevirt-config
namespace: kubevirt
複製代碼
建立 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:
iso-win10
。hostDisk
直接掛載到宿主機以提高性能,若是使用分佈式存儲則體驗很是很差。關於網絡部分,spec.template.spec.networks
定義了一個網絡叫 default
,這裏表示使用 Kubernetes 默認的 CNI。spec.template.spec.domain.devices.interfaces
選擇定義的網絡 default,並開啓 masquerade
,以使用網絡地址轉換 (NAT) 來經過 Linux 網橋將虛擬機鏈接至 Pod 網絡後端。
使用模板文件建立虛擬機:
$ kubectl apply -f win10.yaml
複製代碼
啓動虛擬機實例:
$ virtctl start win10
# 若是 virtctl 安裝爲 kubectl 的插件,命令格式以下:
$ kubectl virt start win10
複製代碼
查看實例運行狀態:
$ 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
複製代碼
執行完上面的命令後,就會打開本地的 VNC 客戶端鏈接到虛擬機:
下面就是安裝正常的安裝步驟往下進行,到選擇硬盤那一步的時候,你會發現沒有一個硬盤可供使用,這時就須要安裝 virtio 驅動了。
不過不用擔憂,virtio 驅動已經被掛載進來了,直接點擊加載驅動程序就能夠安裝驅動了:
安裝好驅動後,硬盤就能正確顯示了:
下面就能夠繼續安裝了。
安裝成功後會自動重啓進行初始化設置,那個熟悉的「海內存知己,天涯若比鄰」又回來了:
設置完成後,進入系統,打開設備管理器,能夠看到有幾個未配置的設備。選擇其中一個右鍵單擊,而後選擇「更新驅動程序」。
選擇「瀏覽個人電腦以查找驅動程序」。
選擇「CD 驅動器(E:)virtio-win-0.1.1」,而後點擊肯定。
設備管理器將自動找到正確的驅動程序,不須要指定驅動程序的路徑。
在提示符下,單擊「安裝」。
其餘的設備驅動能夠複製上面的步驟一一安裝。
若是你的 Kubernetes 集羣 CNI 插件用的是 Calico,這裏會遇到虛擬機沒法聯網的問題。由於 Calico 默認禁用了容器的 ip forward 功能,而 masquerade
須要開啓這個功能才能生效。
咱們只須要修改 Calico 的 ConfigMap 就能夠啓用容器的 ip forward 功能了,執行如下命令打開 configmap calico-config
:
$ kubectl -n kube-system edit cm calico-config
複製代碼
在 CNI 配置文件中加上如下的內容:
"container_settings": {
"allow_ip_forwarding": true
},
複製代碼
修改完的配置文件內容:
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
複製代碼
在系統未安裝好以前,只能用 VNC 來遠程控制,但 VNC 的體驗實在讓人難受。如今系統裝好了,就可使用 Windows 的遠程鏈接協議 RDP(Remote Desktop Protocol) 了。選擇開始 >設置 >系統>遠程桌面,打開啓用遠程桌面就行了。
如今能夠經過 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 <none> <none>
$ telnet 100.92.235.131 3389
Trying 100.92.235.131...
Connected to 100.92.235.131.
Escape character is '^]'.
複製代碼
若是你的本地電腦可以直連 Pod IP
和 SVC IP
,如今就能夠直接經過 RDP 客戶端來遠程鏈接 Windows 了。若是你的本地電腦不能直連 Pod IP
和 SVC IP
,但能夠直連 Kubernetes 集羣的 Node IP
,能夠經過 NodePort
來暴露 RDP 端口。具體操做是建立一個 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 <none> 443/TCP 17d
win10-rdp NodePort 10.98.20.203 <none> 3389:31192/TCP 20m
複製代碼
而後就能夠經過 Node IP
來遠程鏈接 Windows 了。
若是你的本地操做系統是 Windows 10,能夠在任務欄的搜索框中,鍵入「遠程桌面鏈接」,而後選擇「遠程桌面鏈接」。在「遠程桌面鏈接」中,鍵入你想要鏈接的電腦的名稱(從步驟 1),而後選擇「鏈接」。
若是你的本地操做系統是 macOS
,須要在 App Store 中安裝 Microsoft Remote Desktop
。
安裝完以後打開應用,選擇 Add PC:
在 PC name 一欄中輸入 NodeIP+NodePort
,而後點擊 Add。
而後右擊建立好的配置,選擇 Connect:
輸入帳號密碼後就能夠鏈接到 Windows 了。
全屏以後就能夠得到完美的遠程桌面體驗了,盡情玩耍吧!