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
如果不是 Y
或 1
,则需要启用嵌套虚拟化。
步骤如下:
$ 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 中统一管理容器与虚拟机的团队。