【k8s】run VMs on Kubernetes

2022-08-25 18:43:08 浏览数 (1)

概述

本文简单介绍并实践基于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。
代码语言:javascript复制

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),如下命令。
代码语言:javascript复制
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界面上。
代码语言:javascript复制
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以及构建方式如下
代码语言:javascript复制

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即可
代码语言:javascript复制
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镜像。
代码语言:javascript复制

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
代码语言:javascript复制
kubectl create -f cirros.yaml

  • 注意yaml中的Running为true表示创建vm之后启动虚机。如果Running为false的话,则只会创建vm资源,不会启动,需要使用如下命令启动虚机才会创建vm pod并在pod里启动虚机
代码语言:javascript复制
virtctl start <vm-name>

  • 查看testvm以及对应pod是否Running
  • 然后等vmi变成Running并且对应pod变成Running之后,可以使用如下命令连接虚机
代码语言:javascript复制
 virtctl console <vm-name>
  • cirros镜像登录的账号为cirros,密码是gocubsgo。
  • 当然,也可以使用如下命令登录虚机
代码语言:javascript复制
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镜像。注意镜像比较大,下载比较慢。
代码语言:javascript复制
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
代码语言:javascript复制
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
代码语言:javascript复制
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。
代码语言:javascript复制
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中获取镜像
代码语言:javascript复制
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
代码语言:javascript复制
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命令)
代码语言:javascript复制
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命令连接到虚机
代码语言:javascript复制
virtctl console vm1

  • 使用virtctl ssh命令ssh到虚机中。命令如下
代码语言:javascript复制
virtctl ssh fedora@vm1 -i <秘钥文件>

  • 登录到虚机后,在虚拟上ping其他podIP可以ping通

0 人点赞