KubeVirt安装实践
KubeVirt 是 Kubernetes 的虚拟化插件,本指南假设已经安装了 Kubernetes 集群。
1. 部署要求
在开始之前需要满足以下要求:
- 基于最新 Kubernetes 三个版本之一的 Kubernetes 集群或衍生产品(如 OpenShift),以符合 KubeVirt 版本的发布需求。
- Kubernetes apiserver 必须设置
--allow-privileged=true
以便运行 KubeVirt 的特权 DaemonSet。
对于kubeadm部署的kubernetes集群,通过以下命令检查:
sudo vi /etc/kubernetes/manifests/kube-apiserver.yaml
kubectl
客户端工具
容器运行时支持
目前,KubeVirt 支持以下容器运行时:
- containerd
- crio(配合 runv)
其他不使用虚拟化特性的容器运行时也应该可以使用,但上述运行时是主要支持的目标。
与 AppArmor 的集成
在大多数情况下,KubeVirt 可以在启用 AppArmor 的系统上正常运行。然而,有一些已知的使用场景可能需要额外的用户干预。
在启用 AppArmor 的系统上,本地安装的安全配置可能会阻止 KubeVirt 特权容器的执行。这通常会导致 virt-handler
Pod 初始化失败:
$ kubectl get pods -n kubevirt
NAME READY STATUS RESTARTS AGE
virt-api-77df5c4f87-7mqv4 1/1 Running 1 (17m ago) 27m
virt-api-77df5c4f87-wcq44 1/1 Running 1 (17m ago) 27m
virt-controller-749d8d99d4-56gb7 1/1 Running 1 (17m ago) 27m
virt-controller-749d8d99d4-78j6x 1/1 Running 1 (17m ago) 27m
virt-handler-4w99d 0/1 Init:Error 14 (5m18s ago) 27m
virt-operator-564f568975-g9wh4 1/1 Running 1 (17m ago) 31m
virt-operator-564f568975-wnpz8 1/1 Running 1 (17m ago) 31m
$ kubectl logs -n kubevirt virt-handler-4w99d virt-launcher
error: failed to get emulator capabilities
error: internal error: Failed to start QEMU binary /usr/libexec/qemu-kvm for probing: libvirt: error : cannot execute binary /usr/libexec/qemu-kvm: Permission denied
$ journalctl -b | grep DEN
...
May 18 16:44:20 debian audit[6316]: AVC apparmor="DENIED" operation="exec" profile="libvirtd" name="/usr/libexec/qemu-kvm" pid=6316 comm="rpc-worker" requested_mask="x" denied_mask="x" fsuid=107 ouid=0
May 18 16:44:20 debian kernel: audit: type=1400 audit(1652888660.539:39): apparmor="DENIED" operation="exec" profile="libvirtd" name="/usr/libexec/qemu-kvm" pid=6316 comm="rpc-worker" requested_mask="x" denied_mask="x" fsuid=107 ouid=0
...
此时,主机上的 libvirtd 的 AppArmor 配置不允许执行 /usr/libexec/qemu-kvm
二进制文件。希望未来能开箱即用地解决此问题(参见相关问题),但在此之前可以采用几种解决方法。
第一种(也是最简单的)方法是从主机中删除 libvirt 软件包:假设主机是专用的 Kubernetes 节点,通常不需要该软件包。
如果确实需要在主机上保留 libvirt,可以在 libvirtd 的 AppArmor 配置文件中添加以下规则(通常位于 /etc/apparmor.d/usr.sbin.libvirtd
):
]# vim /etc/apparmor.d/usr.sbin.libvirtd
...
/usr/libexec/qemu-kvm PUx,
...
]# apparmor_parser -r /etc/apparmor.d/usr.sbin.libvirtd # or systemctl reload apparmor.service
容器运行时使用的默认 AppArmor 配置通常会拒绝工作负载的挂载调用,这可能会导致无法通过 VirtIO-FS 运行虚拟机。这是一个已知问题。目前的解决方法是将此类虚拟机设为不受限制运行,可通过在 VM 或 VMI 对象中添加以下注解来实现:
annotations:
container.apparmor.security.beta.kubernetes.io/compute: unconfined
验证硬件虚拟化支持
推荐使用支持虚拟化的硬件。您可以使用 virt-host-validate
来确保主机能够运行虚拟化工作负载:
$ 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
...
SELinux 支持
启用 SELinux 的节点需要安装 Container-selinux
。最低版本要求记录在 kubevirt/kubevirt
仓库的 docs/getting-started.md
文件中的“SELinux 支持”部分。
对于未指定 container-selinux
版本的(较旧)发布分支,建议使用版本 2.170.0 或更新版本。
2. 在Kubernetes上安装KubeVirt
KubeVirt和Kubernetes兼容性矩阵
KubeVirt version | 1.30 | 1.29 | 1.28EOL | 1.27EOL | 1.26EOL |
---|---|---|---|---|---|
1.3 | ✓ | ✓ | EOL | - | - |
1.2 | - | ✓ | EOL | EOL | - |
1.1 | - | - | EOL | EOL | EOL |
1.0 | - | - | - | EOL | EOL |
0.59 | - | - | - | - | EOL |
注意:
EOL 表示该 Kubernetes 版本曾被 KubeVirt 支持,但已达到生命周期结束。有关更多详细信息,请参阅 Kubernetes 发布信息。
使用 Operator 安装
可以使用 KubeVirt Operator 安装 KubeVirt,KubeVirt Operator 管理所有 KubeVirt 核心组件的生命周期。下面是安装 KubeVirt 最新正式版本的示例。该版本支持在 x86_64 和 Arm64 平台上部署 KubeVirt。
# Point at latest release
$ export RELEASE=$(curl https://storage.googleapis.com/kubevirt-prow/release/kubevirt/kubevirt/stable.txt)
# Deploy the KubeVirt operator
$ kubectl apply -f https://github.com/kubevirt/kubevirt/releases/download/${RELEASE}/kubevirt-operator.yaml
# Create the KubeVirt CR (instance deployment request) which triggers the actual installation
$ kubectl apply -f https://github.com/kubevirt/kubevirt/releases/download/${RELEASE}/kubevirt-cr.yaml
# wait until all KubeVirt components are up
$ kubectl -n kubevirt wait kv kubevirt --for condition=Available
如果没有硬件虚拟化支持,可以通过在 KubeVirt CR 中将 spec.configuration.developerConfiguration.useEmulation
设置为 true
来启用软件仿真作为替代方案,配置如下:
kubectl edit -n kubevirt kubevirt kubevirt
在 kubevirt.yaml
文件中添加如下内容:
spec:
...
configuration:
developerConfiguration:
useEmulation: true
注意: 在 v0.20.0 版本之前,
kubectl wait
命令的条件名称为 “Ready”,而不是 “Available”。注意: 在 KubeVirt 0.34.2 版本之前,曾使用安装命名空间中的名为
kubevirt-config
的 ConfigMap 来配置 KubeVirt。从 0.34.2 版本起,该方法已被弃用。尽管该 ConfigMap 仍然优先于 CR 中的配置,但它将不再获得更新,建议将所有自定义配置迁移到 KubeVirt CR 的spec.configuration
中。
所有的组件被安装到kubevirt
命名空间:
]# kubectl get pods -n kubevirt
NAME READY STATUS RESTARTS AGE
virt-api-6d4fc3cf8a-b2ere 1/1 Running 0 1m
virt-controller-5d9fc8cf8b-n5trt 1/1 Running 0 1m
virt-handler-vwdjx 1/1 Running 0 1m
...
使用到的容器镜像列表如下,如果离线部署请在各个节点提前导入下面的镜像。本文使用kubevirt 1.3.1版本:
quay.io/kubevirt/virt-operator:v1.3.1
quay.io/kubevirt/virt-api:v1.3.1
quay.io/kubevirt/virt-controller:v1.3.1
quay.io/kubevirt/virt-handler:v1.3.1
quay.io/kubevirt/virt-launcher:v1.3.1
3. 其他安装选项
除了安装到Kubernetes之外,Kubevirt还支持安装到OKD、K3S; 此外,还支持arm64、s390x平台等。
详情参考:https://kubevirt.io/user-guide/cluster_admin/installation/#
4. 安装网络插件(可选)
KubeVirt 本身并不带有额外的网络插件,它只是允许用户使用这些插件。如果您希望将虚拟机连接到多个网络(Multus CNI)或对 L2 网络(OVS CNI)进行完全控制,则需要部署相应的网络插件。有关更多信息,请参考 OVS CNI 安装指南。
注意:
KubeVirt Ansible network playbook 默认会安装这些插件。
本文环境使用calico插件作为网络插件。
5. 限制 KubeVirt 组件节点位置 (可选)
可以通过编辑 KubeVirt CR 来限制 KubeVirt 组件在集群节点上的部署位置:
- KubeVirt 控制平面组件(如 virt-controller 和 virt-api)的部署位置由 KubeVirt CR 中的
.spec.infra.nodePlacement
字段控制。 virt-handler
DaemonSet Pod 的部署位置(以及调度到集群的虚拟机工作负载的部署位置)由 KubeVirt CR 中的.spec.workloads.nodePlacement
字段控制。
对于每个 .nodePlacement
对象,可以配置 .affinity
、.nodeSelector
和 .tolerations
子字段。有关如何使用这些字段的更多信息,请参见 API 参考
中的描述。
例如,要将 virt-controller
和 virt-api
Pod 限制仅在控制平面节点上运行,可以使用以下命令:
kubectl patch -n kubevirt kubevirt kubevirt --type merge --patch '{"spec": {"infra": {"nodePlacement": {"nodeSelector": {"node-role.kubernetes.io/control-plane": ""}}}}}'
要将 virt-handler
Pod 限制仅在具有 “region=primary” 标签的节点上运行,可以使用以下命令:
kubectl patch -n kubevirt kubevirt kubevirt --type merge --patch '{"spec": {"workloads": {"nodePlacement": {"nodeSelector": {"region": "primary"}}}}}'
FAQ
vCPU模式导致virt-handler Pod无法启动
[root@k8s-master1 ~]# kubectl -n kubevirt get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
..
virt-handler-h28br 0/1 Init:CrashLoopBackOff 6 (4m51s ago) 11m 210.244.2.175 k8s-node1 <none> <none>
virt-handler-hzhbd 0/1 Init:CrashLoopBackOff 6 (4m46s ago) 11m 210.244.0.119 k8s-master1 <none> <none>
virt-handler-l442g 0/1 Init:CrashLoopBackOff 6 (4m59s ago) 11m 210.244.1.218 k8s-node2 <none> <none>
virt-handler-r5gfs 0/1 Init:Error 7 (5m7s ago) 11m 210.244.3.82 k8s-node3 <none> <none>
..
[root@k8s-master1 ~]# kubectl -n kubevirt logs virt-handler-h28br
Defaulted container "virt-handler" out of: virt-handler, virt-launcher (init)
Error from server (BadRequest): container "virt-handler" in pod "virt-handler-h28br" is waiting to start: PodInitializing
# 查看virt-launcher日志显示缺少cpu指令集支持。
[root@k8s-master1 ~]# kubectl -n kubevirt logs virt-handler-h28br -c virt-launcher
Fatal glibc error: CPU does not support x86-64-v2
解决方案:
- 本文使用的KVM虚拟机环境,配置vCPU模式为host-model解决。