原文连接: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 了。
全屏以后就能够得到完美的远程桌面体验了,尽情玩耍吧!