概述
本文简单介绍并实践基于k8s平台运行虚机。
本文比较适合自建集群,阿里云,腾讯云,华为云等云厂商的普通云服务器不支持二次虚拟化,无法实现vm on vm。如果只是业务需要虚机,可以直接在云厂商购买虚机使用。
本文测试使用腾讯云的容器服务,节点使用裸金属云服务器。
应用场景
- 统一的k8s平台,k8s上可以运行容器,也可以运行虚机
- 有些重型应用需要部署在虚机上
- 虚机拥有更好的隔离性
- etc
开源项目
开源的基于k8s的虚机解决方案有kubevirt和virtlet,其中kubevirt使用CRD扩展k8s API,virtlet则实现了CRI接口。
kubevirt
kubevirt使用CRD扩展k8s api,控制面以add-on的形式部署到k8s集群。
项目:https://github.com/kubevirt/kubevirt
文档:https://kubevirt.io/
架构:
virtlet
virtlet是较早开源的基于k8s平台的虚机解决方案,实现了CRI接口,组件部署需要先给节点部署cri-proxy,cri-proxy会根据配置选择dockershim或者virtlet,然后再部署daemonset
项目:https://github.com/Mirantis/virtlet
文档:https://docs.virtlet.cloud/
架构:
kubevirt/virtlet
kubevirt | virtlet | |
---|---|---|
公司 | redhat | Mirantis |
开源项目 | https://github.com/kubevirt/kubevirt | https://github.com/Mirantis/virtlet |
现状 | 持续更新 | 3年未更新 |
版本 | v0.56.0 | v1.5.1 |
star | 3.5K | 686 |
同时运行虚机/容器 | 支持 | 支持 |
实现方式 | CRD add-on | CRI |
组件部署 | 简单(add-on) | 复杂(worker节点配置 add-on) |
使用方法 | CR,扩展性强 | pod annotation(原生workload) |
虚机方案 | libvirt API | libvirt API |
cloudInit | 支持 | 支持 |
多网卡 | 支持(依赖网络插件) | 支持(依赖网络插件) |
...... |
kubevirt实践
注意腾讯云只有裸金属云服务器的标准集群可以用于kubevirt/virtlet使用测试。
- 标准集群普通云服务器不支持二次虚拟化,无法测试。
- serverless集群由于节点都是虚拟的超级节点不支持Daemonset原生资源,并且创建的pod也是先申请虚机然后在虚机里起容器(不支持二次虚拟化)
- 边缘集群用于管理边缘节点,无法部署kubevirt/virtlet控制面板组件
创建tke集群
参考文档:https://cloud.tencent.com/document/product/457/32189
- 腾讯云上创建tke集群(这里工作节点选择黑石服务器,普通云服务器不支持二次虚拟化)
- 以托管标准集群为例【注意:托管集群区别于独立集群,master组件由腾讯云托管。标准集群区别于serverless集群和边缘集群,支持原生节点注册和超级节点管理】,在"容器服务"->"集群",点击"新建"
- 选择"标准节点",然后点击"创建"
- 配置好集群名(以williamji-baremetal为例),集群版本,运行时,私有网络以及容器网络之后点击下一步
- 配置集群规模,以及worker节点配置,机型这里测试选择裸金属服务器。配置好之后点击下一步
- 配置好worker节点登录方式以及对应秘钥/密码之后点击下一步
- 配置集群组件之后点击下一步,组件在集群创建后也可以添加,这里使用默认组件,然后下一步
- 勾选"我已经阅读并同意"后点击完成
- 等集群创建好之后可以在"容器服务"->"集群"中搜索并查看对应集群
- 点击集群,进入集群查看集群相关菜单以及相应的资源
kubevirt组件部署
参考kubevirt文档:https://kubevirt.io/quickstart_cloud/
- 部署kubevirt组件的CRD和kubevirt-operator。
export VERSION=$(curl -s https://api.github.com/repos/kubevirt/kubevirt/releases | grep tag_name | grep -v -- '-rc' | sort -r | head -1 | awk -F': ' '{print $2}' | sed 's/,//' | xargs)
echo $VERSION
kubectl create -f https://github.com/kubevirt/kubevirt/releases/download/${VERSION}/kubevirt-operator.yaml
- 部署好之后会多个kubevirts.kubevirt.io的CRD和virt-operator的deployment,其中kubevirt这个CRD和operator是用来部署kubevirt组件的。
- 部署kubevirt组件,也就是创建一个kubevirt实例(CR),如下命令。
export VERSION=$(curl -s https://api.github.com/repos/kubevirt/kubevirt/releases | grep tag_name | grep -v -- '-rc' | sort -r | head -1 | awk -F': ' '{print $2}' | sed 's/,//' | xargs)
echo $VERSION
kubectl create -f https://github.com/kubevirt/kubevirt/releases/download/${VERSION}/kubevirt-cr.yaml
- 部署好kubevirt组件之后,会多一个kubevirt资源。然后virt-operator会创建对应的kubevirt组件,包含deployment:kubevirt/virt-api,deployment:kubevirt/virt-controller以及daemonset:kubevirt/virt-handler以及kubevirt的vm对应CRD资源
- 等待kubevirt所有组件pod运行正常之后,查看节点信息,注意节点里有可分配的kvm和tun等设备插件,如果是可分配的kvm设备是0表示节点不支持虚拟化,需要开启虚拟化。可以通过virt-hander日志查看设备插件信息
- 安装kubevirt命令行工具virtctl,该命令用于管理以及访问虚机。实际上virtctl下载地址就在github的release界面上。
VERSION=$(kubectl get kubevirt.kubevirt.io/kubevirt -n kubevirt -o=jsonpath="{.status.observedKubeVirtVersion}")
ARCH=$(uname -s | tr A-Z a-z)-$(uname -m | sed 's/x86_64/amd64/') || windows-amd64.exe
echo ${ARCH}
curl -L -o virtctl https://github.com/kubevirt/kubevirt/releases/download/${VERSION}/virtctl-${VERSION}-${ARCH}
chmod x virtctl
sudo install virtctl /usr/local/bin
- 安装好virtctl命令之后,可以查看virtctl的help信息
准备container-disk镜像
kubevirt提供了测试的container-disk镜像可以直接用于vm创建。参考https://github.com/kubevirt/kubevirt/blob/main/containerimages/container-disk-images.md
- iso引导文件可以直接用于kubevirt的vm创建,创建好vm之后需要vnc登录虚机完成引导(以下windows测试直接使用的iso文件)
- qcow2云镜像可以用来挂载启动虚机,网上一般都会有发行版的cloudimage,如果有iso镜像想转换成qcow2镜像,比较麻烦,依赖libvirt相关工具。参考文档:https://www.ibm.com/docs/en/cic/1.1.2?topic=images-creating-from-iso-kvm
- 把qcow2镜像构建到容器镜像,测试dockerfile以及构建方式如下
cat > Dockerfile <<EOF
FROM kubevirt/container-disk-v1alpha
ADD fedora32.qcow2 /disk/
EOF
docker build -t kubevirt/fedora-sriov-testing:latest .
- 推荐使用CDI(CRD),以声明的方式在pvc上构建虚机镜像挂载虚机。项目:https://github.com/kubevirt/containerized-data-importer
CDI组件部署
CDI使用CRD扩展api,用于将虚拟机映像或其他数据填充PVC来挂载虚机。数据可以来自不同的来源:URL、容器镜像仓库、或来自客户端的上传。
- CDI部署方法参考:https://kubevirt.io/labs/kubernetes/lab2.html。将crd和cr资源部署好之后查看状态OK即可
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
- CDI组件部署好之后,先创建CRD,然后创建CR(cdi),operator会创建cdi相关组件。
使用container-disk镜像直接运行虚机(cirros镜像)
参考文档:https://kubevirt.io/labs/kubernetes/lab1.html
- 使用测试yaml如下。该vm资源使用了quay.io/kubevirt/cirros-container-disk-demo这个container-disk镜像。
cat > cirros.yaml <<EOF
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
name: testvm
spec:
running: true
template:
metadata:
labels:
kubevirt.io/size: small
kubevirt.io/domain: testvm
spec:
domain:
devices:
disks:
- name: containerdisk
disk:
bus: virtio
- name: cloudinitdisk
disk:
bus: virtio
interfaces:
- name: default
masquerade: {}
resources:
requests:
memory: 64M
networks:
- name: default
pod: {}
volumes:
- name: containerdisk
containerDisk:
image: quay.io/kubevirt/cirros-container-disk-demo
- name: cloudinitdisk
cloudInitNoCloud:
userDataBase64: SGkuXG4=
EOF
- 使用kubectl部署该yaml
kubectl create -f cirros.yaml
- 注意yaml中的Running为true表示创建vm之后启动虚机。如果Running为false的话,则只会创建vm资源,不会启动,需要使用如下命令启动虚机才会创建vm pod并在pod里启动虚机
virtctl start <vm-name>
- 查看testvm以及对应pod是否Running
- 然后等vmi变成Running并且对应pod变成Running之后,可以使用如下命令连接虚机
virtctl console <vm-name>
- cirros镜像登录的账号为cirros,密码是gocubsgo。
- 当然,也可以使用如下命令登录虚机
virtctl ssh --local-ssh=true cirros@testvmi
运行测试虚机(Windows虚机 ISO镜像为例)
kubevirt windows参考文档:https://kubevirt.io/2020/KubeVirt-installing_Microsoft_Windows_from_an_iso.html
注意:该测试受客户端环境影响,vm启动成功但是挂载的iso操作系统没有安装好。
- 下载ISO镜像。注意镜像比较大,下载比较慢。
ISO镜像下载网址:https://info.microsoft.com/ww-landing-windows-server-2012-R2.html
Note: 需要输入个人信息可以免费试用180天
cloudimage镜像下载网址:https://cloudbase.it/windows-cloud-images/
- 通过virtctl工具上传iso镜像到pvc中,其中image-path表示本地ISO镜像文件,--uploadproxy-url表示service: cdi/
uploadproxy的集群服务
代码语言:javascript复制virtctl image-upload
--image-path=./9600.17050.WINBLUE_REFRESH.140317-1640_X64FRE_SERVER_EVAL_EN-US-IR3_SSS_X64FREE_EN-US_DV9.ISO
--pvc-name=iso-win2k12
--access-mode=ReadOnlyMany
--pvc-size=5G
--uploadproxy-url=https://10.96.164.35:443
--insecure
--wait-secs=240
- virtctl image-upload是将客户端的ios文件上传到pvc绑定的pv上,该上传操作会经过apiserver,大镜像比较慢。测试时直接将下载好的iso文件存放到节点上,并将对应目录创建为hostpath类型的pv,然后创建pvc绑定pv
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-windows-iso
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/mnt/windows"
type: DirectoryOrCreate
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: "pvc-windows-iso"
labels:
app: containerized-data-importer
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
- 创建pvc和pv用于虚机操作系统的安装,这里也使用hostpath类型的pv
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-windows-hd
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 20Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/mnt/windows-hd"
type: DirectoryOrCreate
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: "pvc-windows-hd"
labels:
app: containerized-data-importer
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
- 创建vm(cr)资源,vm会使用存储iso文件的pvc,以及用于操作系统安装的pvc。这里字段running为true表示vm创建好后会自动启动,vm创建好后,controller会listwatch并创建vm pod。
apiVersion: kubevirt.io/v1alpha3
kind: VirtualMachine
metadata:
name: win2k12-iso
spec:
running: true
template:
metadata:
labels:
kubevirt.io/domain: win2k12-iso
spec:
domain:
cpu:
cores: 4
devices:
disks:
- bootOrder: 1
cdrom:
bus: sata
name: cdromiso
- disk:
bus: virtio
name: harddrive
- cdrom:
bus: sata
name: virtiocontainerdisk
machine:
type: q35
resources:
requests:
memory: 8G
volumes:
- name: cdromiso
persistentVolumeClaim:
claimName: pv-windows-iso
- name: harddrive
persistentVolumeClaim:
claimName: pv-windows-hd
- containerDisk:
image: kubevirt/virtio-container-disk
name: virtiocontainerdisk
- vm创建好之后,查看vm以及对应的pod是否正常
- 测试console能正常连接
- 测试vnc,正常情况下会弹出windows的安装窗口,测试环境受限制弹不出来,无法继续安装。
- 因为windows iso镜像还没安装,所以虚机也没起来,只是qemu-kvm进程运行正常。
- 所以对应的windows虚机IP无法ping通。
运行测试虚机(fedora虚机 initcloud)
参考文档:https://kubevirt.io/labs/kubernetes/lab2.html
- 创建fedora的pvc,使用annotation配置fedora的cloudimage镜像url,利用了cdi从url中获取镜像
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: "fedora"
labels:
app: containerized-data-importer
annotations:
cdi.kubevirt.io/storage.import.endpoint: "https://download.fedoraproject.org/pub/fedora/linux/releases/33/Cloud/x86_64/images/Fedora-Cloud-Base-33-1.2.x86_64.raw.xz"
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
- 这里pvc绑定使用的hostpath类型的pv,当然有sc提供的pv(cbs,cfs,cos)也可以,最终会在pv的目录下创建下载的cloudimage
apiVersion: v1
kind: PersistentVolume
metadata:
name: task-pv-volume
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/mnt/data"
type: DirectoryOrCreate
- 可以看到pvc启动后有importer-<pvcname>对应的pod已经运行,该pod会下载pvc中annotation的云镜像到pv挂载中。
- 查看importer-<pvcname>的pod日志,等待pod处理完成,处理快慢依赖网速。pod日志里会有Prometheus打印的处理进度,处理完成后会有相关日志,然后pod会被删除。【注意:这里只是测试cdi的能力,建议还是直接拿下载好的cloudimage打成containerdisk镜像使用】
- 然后创建vm挂载该pvc。该vm资源以virtio的形式挂载cloudimage,并且把cloudinit也挂载到虚机中。其中cloudinit里有公钥,虚机启动成功后可以用私钥登录。(ssh公钥秘钥的生成可以使用:ssh-keygen命令)
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
generation: 1
labels:
kubevirt.io/os: linux
name: vm1
spec:
running: true
template:
metadata:
creationTimestamp: null
labels:
kubevirt.io/domain: vm1
spec:
domain:
cpu:
cores: 2
devices:
disks:
- disk:
bus: virtio
name: disk0
- cdrom:
bus: sata
readonly: true
name: cloudinitdisk
machine:
type: q35
resources:
requests:
memory: 1024M
volumes:
- name: disk0
persistentVolumeClaim:
claimName: fedora
- cloudInitNoCloud:
userData: |
#cloud-config
hostname: vm1
ssh_pwauth: True
disable_root: false
ssh_authorized_keys:
- ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCzJrjWS X39RGxRiyQkUFFzcHiw5zPg2ASHRHN wF7418yd XqZ4PWK8oM2z0Fy4pX MRMgH36qUhcx0qO6N1UMTsYQr0vbEJ1 6NGrgR4E3Mj3852H3dncVRjcrQL0 JdSFAzpBi/xQnqLS2BpTE0q4rh6kOGPhJ/YhhBAUwxj633o37eiBNZybmkb2XkxqG kN0513QzPyaIfMwQ1OMe2xTiTeDJIWk1TZ8EJtp6PGxDy CHCZCtKsE9jzohM4oZF2bBGW9A gkwxoKAsHAZ0xD3xQFU2xRAKEgl16VNfjgeBZnpbRVIPlhlpQXWyFlJLLqMiLbt0wHhBLB9HCNZ williamji@VM-46-151-centos
name: cloudinitdisk
- vm资源创建成功后,可以查看vm状态是否Running,对应的virt-launcher pod是否Running
- 等launcher pod和vm状态Running,表示虚机运行正常。
- 使用virtctl命令连接到虚机
virtctl console vm1
- 使用virtctl ssh命令ssh到虚机中。命令如下
virtctl ssh fedora@vm1 -i <秘钥文件>
- 登录到虚机后,在虚拟上ping其他podIP可以ping通