1. 简介

Kubernetes (K8s) 是一个开源的容器编排系统,能够将容器以 Pod 的形式进行调度和管理。它的控制平面由控制器和管理 Pod 组成,驱动整个 集群 的运行,使得用户的应用 Pod 可以被调度到任意节点上运行。此外,Kubernetes 还支持通过自定义资源类型、控制器和代理进行功能扩展。

KubeVirt 是 Kubernetes 的一个开源扩展,它允许用户直接在集群中管理虚拟机(VM)。

在本文中,我们通过一个基础部署和使用示例来介绍 KubeVirt。首先,我们会了解该项目及其主要功能,然后逐步部署 KubeVirt,最后演示如何在 Kubernetes 中创建和管理虚拟机。

本文的测试环境为 Debian 12(Bookworm),使用 GNU Bash 5.2.15。除非特别说明,大部分步骤在 POSIX 兼容环境中均应适用。


2. KubeVirt 概述

KubeVirt 项目的目标是将容器化与虚拟化管理整合进 Kubernetes 框架中:

 +---------------------+
 | KubeVirt            |
=========================
 | Orchestration (K8s) |
 +---------------------+
 | Scheduling (K8s)    |
 +---------------------+
 | Container Runtime   |
=========================
 | Operating System    |
 +---------------------+
 | (Virtual)           |
=========================
 | Physical            |
 +---------------------+

具体来说,KubeVirt 支持声明式地创建和管理虚拟机。

为此,它实现了一些类似 Pod 的自定义资源类型:

  • **VirtualMachine (VM)**:虚拟机定义
  • **VirtualMachineInstance (VMI)**:虚拟机实例
  • **VirtualMachineInstanceReplicaSet (VMIRS)**:基于 VMI 的副本集

此外,它还引入了一些控制器组件来处理这些资源:

  • virt-controller:核心虚拟化组件,负责监控 VMI 并管理 VM Pod
  • virt-launcher:负责 VMI Pod 的实际启动和信号处理
  • virt-handler:作为守护进程运行在每个节点上,响应故障、重启等事件
  • libvirtd:virt-launcher 依赖该守护进程进行 VMI 生命周期管理

有了这些扩展,我们就可以在 Kubernetes 中创建由 KubeVirt 管理的 VMI Pod。

但为了确保节点层面的正常运行,KubeVirt 还需要一个节点级别的守护进程 virt-handler

一旦配置完成,我们就可以在 Kubernetes 中进行如下操作:

  • 通过定义创建 VM
  • 调度 VM
  • 启动 VM
  • 停止 VM
  • 删除 VM

当然,这些操作也继承了 Kubernetes 的自动化能力:

  • Pod 控制
  • 存储管理
  • 网络处理

值得一提的是,KubeVirt 支持仅使用 VM 或 VM 与容器混合部署虚拟化应用

接下来,我们来看看如何部署 KubeVirt。


3. KubeVirt 部署

了解其内部机制后,我们来实际部署 KubeVirt。

3.1. 部署 Kubernetes

由于 Kubernetes 的安装不是本文重点,我们使用 minikube 快速搭建一个单节点集群。虽然我们也可以不使用 minikube 来 部署 Kubernetes,但 minikube 能让我们更快地拥有一个可用环境。

首先安装 minikube:

$ curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 && chmod +x minikube && sudo mv minikube /usr/local/bin/

然后启动集群:

$ minikube start --cni=flannel

如果在虚拟机中运行,可以加上 --driver=none 参数。但需要注意,在虚拟化环境中运行虚拟机还需要启用嵌套虚拟化或使用模拟

接下来设置 kubectl 别名:

$ alias kubectl='minikube kubectl --'

此时我们应能看到一个正常运行的 Kubernetes 集群:

$ kubectl get all --all-namespaces
NAMESPACE     NAME                               READY   STATUS    RESTARTS   AGE
kube-system   pod/coredns-5dd5756b68-z5pqr       1/1     Running   0          2m35s
kube-system   pod/etcd-xost                      1/1     Running   0          2m47s
kube-system   pod/kube-apiserver-xost            1/1     Running   0          2m47s
kube-system   pod/kube-controller-manager-xost   1/1     Running   0          2m47s
kube-system   pod/kube-proxy-cvrzj               1/1     Running   0          2m35s
kube-system   pod/kube-scheduler-xost            1/1     Running   0          2m47s
kube-system   pod/storage-provisioner            1/1     Running   0          2m45s

NAMESPACE     NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
default       service/kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP                  2m49s
kube-system   service/kube-dns     ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP   2m47s

NAMESPACE     NAME                        DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
kube-system   daemonset.apps/kube-proxy   1         1         1       1            1           kubernetes.io/os=linux   2m47s

NAMESPACE     NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
kube-system   deployment.apps/coredns   1/1     1            1           2m47s

NAMESPACE     NAME                                 DESIRED   CURRENT   READY   AGE
kube-system   replicaset.apps/coredns-5dd5756b68   1         1         1       2m36s

接下来,我们开始部署 KubeVirt。

3.2. 使用 minikube 插件部署 KubeVirt

minikube 支持直接启用 kubevirt 插件:

$ minikube addons enable kubevirt

我们可以通过以下命令查看安装状态:

$ kubectl logs pod/kubevirt-install-manager --namespace kube-system

不过,这种方法不适用于生产环境部署。此外,某些版本的 minikube 在启用 kubevirt 插件时可能出现问题。因此,我们更推荐使用 kubectl 方式部署。

3.3. 使用 kubectl 部署 KubeVirt

首先获取最新稳定版本号:

$ VERSION="$(curl --silent https://storage.googleapis.com/kubevirt-prow/release/kubevirt/kubevirt/stable.txt)"

然后通过 kubectl 部署 operator:

$ kubectl create --filename="https://github.com/kubevirt/kubevirt/releases/download/${VERSION}/kubevirt-operator.yaml"

输出示例:

namespace/kubevirt created
customresourcedefinition.apiextensions.k8s.io/kubevirts.kubevirt.io created
priorityclass.scheduling.k8s.io/kubevirt-cluster-critical created
clusterrole.rbac.authorization.k8s.io/kubevirt.io:operator created
serviceaccount/kubevirt-operator created
role.rbac.authorization.k8s.io/kubevirt-operator created
rolebinding.rbac.authorization.k8s.io/kubevirt-operator-rolebinding created
clusterrole.rbac.authorization.k8s.io/kubevirt-operator created
clusterrolebinding.rbac.authorization.k8s.io/kubevirt-operator created
deployment.apps/virt-operator created

接着部署自定义资源定义:

$ kubectl create --filename="https://github.com/kubevirt/kubevirt/releases/download/${VERSION}/kubevirt-cr.yaml"

输出示例:

kubevirt.kubevirt.io/kubevirt created

此时,KubeVirt 已部署完成。

3.4. 查看 KubeVirt 集群状态

我们可以查看 kubevirt 命名空间下的资源状态:

$ kubectl get all --namespace kubevirt

输出示例:

NAME                                   READY   STATUS    RESTARTS   AGE
pod/virt-api-668b69dd4-4tqsr           1/1     Running   0          69m
pod/virt-controller-7b6686f4ff-jfgpf   1/1     Running   0          69m
pod/virt-controller-7b6686f4ff-vtzwd   1/1     Running   0          69m
pod/virt-handler-6dkb5                 1/1     Running   0          69m
pod/virt-operator-656b9658fc-lsb4x     1/1     Running   0          105m
pod/virt-operator-656b9658fc-wpm9f     1/1     Running   0          105m

NAME                                  TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
service/kubevirt-operator-webhook     ClusterIP   10.108.24.17            443/TCP   69m
service/kubevirt-prometheus-metrics   ClusterIP   None                    443/TCP   69m
service/virt-api                      ClusterIP   10.107.156.67           443/TCP   69m
service/virt-exportproxy              ClusterIP   10.99.78.172            443/TCP   69m

NAME                          DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
daemonset.apps/virt-handler   1         1         1       1            1           kubernetes.io/os=linux   69m

NAME                              READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/virt-api          1/1     1            1           69m
deployment.apps/virt-controller   2/2     2            2           69m
deployment.apps/virt-operator     2/2     2            2           105m

NAME                                         DESIRED   CURRENT   READY   AGE
replicaset.apps/virt-api-668b69dd4           1         1         1       69m
replicaset.apps/virt-controller-7b6686f4ff   2         2         2       69m
replicaset.apps/virt-operator-656b9658fc     2         2         2       105m

NAME                            AGE   PHASE
kubevirt.kubevirt.io/kubevirt   70m   Deployed

也可以通过以下命令查看部署状态:

$ kubectl get kubevirt.kubevirt.io/kubevirt --namespace kubevirt --output=jsonpath="{.status.phase}"
Deployed

3.5. 嵌套虚拟化或模拟

如果我们在虚拟机中运行 KubeVirt,则需要启用嵌套虚拟化或使用模拟。

我们可以通过 /proc 文件系统检查是否启用:

  • Intel:/sys/module/kvm_intel/parameters/nested
  • AMD:/sys/module/kvm_amd/parameters/nested

示例:

$ cat /sys/module/kvm_intel/parameters/nested
Y

如果不是 Y1,则需要启用嵌套虚拟化。

步骤如下:

$ CPU=intel
$ modprobe --remove kvm_$CPU
$ modprobe kvm_$CPU nested=1

持久化设置:

$ cat /etc/modprobe.d/kvm.conf
options kvm_$CPU nested=1

如果不支持嵌套虚拟化,可以启用模拟:

$ kubectl --namespace kubevirt patch kubevirt kubevirt --type=merge --patch '{"spec":{"configuration":{"developerConfiguration":{"useEmulation":true}}}}'

虽然性能较低,但至少可以继续部署。

3.6. 安装 virtctl

virtctl 是 KubeVirt 的 CLI 工具,类似于 kubectl。

安装步骤如下:

$ VERSION=$(kubectl get kubevirt.kubevirt.io/kubevirt --namespace kubevirt --output=jsonpath="{.status.observedKubeVirtVersion}")
$ ARCH=$(uname --kernel-name | tr A-Z a-z)-$(uname --machine | sed 's/x86_64/amd64/') || windows-amd64.exe
$ curl --location --output virtctl "https://github.com/kubevirt/kubevirt/releases/download/${VERSION}/virtctl-${VERSION}-${ARCH}"
$ chmod +x virtctl
$ sudo install virtctl /usr/local/bin

现在我们就可以使用 virtctl 进行操作了。


4. KubeVirt 示例演示

接下来我们演示如何创建一个虚拟机。

4.1. 创建 VM 定义文件

创建一个简单的 VM 定义文件 xvm.yaml

apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: xvm
spec:
  running: false
  template:
    metadata:
      labels:
        kubevirt.io/size: small
        kubevirt.io/domain: xvm
    spec:
      domain:
        devices:
          disks:
            - name: containerdisk
              disk:
                bus: virtio
            - name: cloudinitdisk
              disk:
                bus: virtio
          interfaces:
          - name: default
            bridge: {}
        resources:
          requests:
            memory: 64M
      networks:
      - name: default
        pod: {}
      volumes:
        - name: containerdisk
          containerDisk:
            image: quay.io/kubevirt/cirros-container-disk-demo
        - name: cloudinitdisk
          cloudInitNoCloud:
            userDataBase64: SGlrcyBHZXJnYW5vdlxu

这个定义使用了一个 containerDisk,类似于容器镜像,不持久化数据,但可以轻松从镜像仓库拉取。

4.2. 部署 VM

部署该虚拟机:

$ kubectl apply -f xvm.yaml
virtualmachine.kubevirt.io/xvm created

查看状态:

$ kubectl get vms
NAME   AGE   STATUS    READY
xvm    4m    Stopped   False

4.3. 启动并连接 VM

使用 virtctl 启动虚拟机:

$ virtctl start xvm
VM xvm was scheduled to start

也可以使用 kubectl:

$ kubectl patch virtualmachine xvm --type merge --patch='{"spec":{"running":true}}'

查看 VMI 状态:

$ kubectl get vmis
NAME   AGE   PHASE     IP            NODENAME   READY
xvm    2m    Running   10.244.0.16   xost       True

连接到虚拟机控制台:

$ virtctl console xvm

CirrOS 是一个演示系统,登录后可以使用 ^] 退出。

4.4. 管理 VM

停止虚拟机:

$ virtctl stop xvm

删除虚拟机:

$ kubectl delete vm xvm

5. 小结

KubeVirt 是 Kubernetes 的一个强大扩展,允许我们在集群中管理虚拟机。尽管容器化技术已广泛应用,但虚拟化在许多场景中仍然不可或缺。将虚拟机管理整合进 Kubernetes 可以极大提升运维效率。

✅ 优点:

  • 与 Kubernetes 无缝集成
  • 支持声明式管理
  • 支持容器与虚拟机混合部署

⚠️ 注意事项:

  • 需启用嵌套虚拟化或使用模拟
  • 性能可能不如原生虚拟化

KubeVirt 是一个值得尝试的云原生虚拟化方案,适合需要在 Kubernetes 中统一管理容器与虚拟机的团队。


原始标题:Deploying and Using KubeVirt