主题
KubeVirt 从入门到精通 —— 系统全面教材
版本: v1.0(2026-09-03) 适用版本: KubeVirt v1.9.x、CDI v1.60.x、Kubernetes/RKE2 v1.28+ 配套实战文档:
kubevirt-practical-operations-guide.md(部署实施与运维专题) 关联现网文档:../rke2-kubevirt-deployment-guide.md、../cdi-offline-deployment-guide.md、../kubevirt-nas-storage-guide.md、../kubevirt-storage-ha-guide.md、../kubevirt-network-ssh-password-guide.md
目录
第一部分 入门篇
第二部分 进阶篇
第三部分 精通篇
附录
第一部分 入门篇
1. 认识 KubeVirt
1.1 什么是 KubeVirt
KubeVirt 是一个运行在 Kubernetes 之上的虚拟化扩展平台。它把"虚拟机"抽象成 Kubernetes 的自定义资源(CRD),让你可以像管理 Pod 一样,用 kubectl / YAML / GitOps 的方式声明、创建、启停、迁移虚拟机。
一句话定位:
容器编排平台 + 传统虚拟机负载 = KubeVirt。 它不是模拟器,底层就是 KVM + QEMU,性能等同原生 KVM 虚拟机。
1.2 为什么需要 KubeVirt
| 痛点 | KubeVirt 的解法 |
|---|---|
| 存量传统应用(单体、Windows、旧中间件)无法容器化 | 以虚拟机形态继续运行,与容器同平台管理 |
| 同时维护 K8s 和 OpenStack/VMware 两套平台,团队割裂 | 一套 K8s 平台统一管理容器与虚拟机 |
| 虚拟机的创建/扩缩/迁移依赖手工操作 | 全部 API 化、声明式、可 GitOps |
| CI/CD 流水线无法覆盖虚拟机 | 与容器走同一套流水线、镜像仓库、监控告警 |
1.3 与传统虚拟化平台对比
| 维度 | libvirt/KVM 裸用 | OpenStack | PVE | KubeVirt |
|---|---|---|---|---|
| 管理接口 | virsh/XML | Horizon/API | Web UI | kubectl + CRD(声明式) |
| 编排能力 | 无 | 有(重) | 弱 | 原生继承 K8s 编排 |
| 网络 | Linux Bridge | Neutron(复杂) | SDN 可选 | 复用 CNI + Multus |
| 存储 | 本地文件/共享盘 | Cinder | ZFS/Ceph | 复用 CSI/PVC(任何存储后端) |
| 部署重量 | 轻 | 极重 | 中 | 轻(一组 Operator 组件) |
| 适合场景 | 单机/小规模 | 大型私有云 | 中小虚拟化 | 已有 K8s 团队承载 VM 负载 |
1.4 典型适用场景
- 存量传统应用迁移过渡(先搬上平台,再逐步容器化);
- 需要完整 OS 的负载:Windows 应用、需要特定内核模块的应用;
- 开发测试环境快速发放虚拟机(模板 + 克隆秒级开盘);
- 边缘/小规模场景替代重型虚拟化平台。
不适用场景:追求极致虚拟机密度与完整 IaaS 能力(计费、多租户网络、镜像市场) 的大型私有云,仍建议评估 OpenStack 或商业平台。
2. 核心概念与整体架构
2.1 整体架构图
kubectl / virtctl / GitOps
│
┌─────────▼─────────┐
│ Kubernetes API │
│ Server (CRD 扩展) │
└─────────┬─────────┘
webhook/admission │ watch 资源
┌───────────────┼────────────────────┐
│ │ │
┌───────▼──────┐ ┌─────▼────────┐ ┌───────▼────────┐
│ virt-api │ │virt-controller│ │ virt-operator │
│ (校验/转换/ │ │ (VM→VMI→ │ │ (组件生命周期/ │
│ console代理)│ │ launcher调度)│ │ 升级/自愈) │
└──────────────┘ └─────┬────────┘ └────────────────┘
│ 为每个 VMI 创建
┌─────────▼─────────┐
│ virt-launcher Pod │ ← 每个运行中 VM 一个 Pod
│ ┌──────────────┐ │
│ │ libvirtd+QEMU│ │
│ │ (KVM 客户机) │ │
│ └──────────────┘ │
└─────────┬─────────┘
│ 节点内管理
┌─────────▼─────────┐
│ virt-handler │ ← DaemonSet,每节点一个
│ (节点代理:域定义、 │
│ 迁移、磁盘热插拔) │
└───────────────────┘2.2 核心组件职责
| 组件 | 部署形态 | 职责 | 挂了会怎样 |
|---|---|---|---|
| virt-operator | Deployment(2 副本) | 管理 KubeVirt CR,部署/升级/自愈其余所有组件 | 存量 VM 无感;无法升级/自愈 |
| virt-api | Deployment(2 副本) | 校验/变更 Webhook、子资源 API(console/vnc 代理)、凭证签发 | 存量 VM 无感;新建/控制台不可用 |
| virt-controller | Deployment(2 副本) | 大脑:watch VM/VMI,创建 virt-launcher Pod、处理迁移/驱逐 | 存量 VM 无感;无法启动新 VM |
| virt-handler | DaemonSet(每节点 1 个) | 节点代理:把 VMI 规格翻译为域定义交给 launcher、迁移目标端接收、磁盘热插拔 | 该节点无法启停 VM |
| virt-launcher | 每 VMI 一个 Pod | 内含 libvirtd + QEMU,真正运行客户机;Pod 消亡 = VM 停止 | 该 VM 停止 |
| virt-exportproxy | Deployment(2 副本) | 数据导出(VirtualMachineExport)的入口代理 | 导出功能不可用 |
| virt-template-* | Deployment | 模板 API(可选能力) | 模板功能不可用 |
关键理解:virt-launcher Pod 与 VMI 是 1:1 关系。删除这个 Pod 等于强制关机; Pod 被调度到其他节点等于 VM 冷迁移。理解这一点后,很多排障思路与容器完全一致。
2.3 核心 CRD 一览
| CRD | 缩写 | 作用 | 使用频率 |
|---|---|---|---|
virtualmachines.kubevirt.io | vm | 虚拟机定义(期望状态),可反复启停 | ⭐⭐⭐⭐⭐ |
virtualmachineinstances.kubevirt.io | vmi | 运行中的实例(类似 Pod 之于 Deployment) | ⭐⭐⭐⭐⭐ |
virtualmachineinstancemigrations.kubevirt.io | vmim | 一次热迁移任务 | ⭐⭐⭐ |
virtualmachineinstancereplicasets.kubevirt.io | vmirs | VM 副本集(无状态批量) | ⭐⭐ |
virtualmachinepools.pool.kubevirt.io | vmpool | VM 池(支持扩缩与滚动更新) | ⭐⭐ |
virtualmachineclones.clone.kubevirt.io | vmclone | 一键克隆 VM 及其磁盘 | ⭐⭐⭐ |
virtualmachinesnapshots.snapshot.kubevirt.io | vmsnapshot | VM 快照 | ⭐⭐⭐ |
virtualmachinerestores.snapshot.kubevirt.io | vmrestore | 从快照恢复 | ⭐⭐⭐ |
virtualmachineexports.export.kubevirt.io | vmexport | 把 VM 磁盘导出为镜像/文件 | ⭐⭐⭐ |
datavolumes.cdi.kubevirt.io | dv | CDI:磁盘导入/克隆/上传/空白盘 | ⭐⭐⭐⭐ |
kubevirts.kubevirt.io | kv | KubeVirt 平台自身配置 | ⭐⭐ |
virtualmachineclusterinstancetypes.instancetype.kubevirt.io | vmclusterinstancetype | 规格模板(类似 EC2 实例类型) | ⭐⭐ |
migrationpolicies.migrations.kubevirt.io | migrationpolicy | 迁移策略分组 | ⭐ |
2.4 一次"创建并启动 VM"的完整链路
① kubectl apply vm.yaml (spec.runStrategy: Always)
│
② virt-api webhook 校验字段、注入默认值
│
③ virt-controller 发现 VM 需要运行 → 创建 VMI 对象
│
④ virt-controller 创建 virt-launcher Pod(资源请求 = VM 的 CPU/内存)
│
⑤ Pod 调度到节点 → kubelet 拉起容器
│
⑥ 该节点的 virt-handler 读取 VMI → 生成域定义 → 通知 launcher 内 libvirtd
│
⑦ QEMU 启动客户机,挂载 PVC 磁盘、接入 CNI 网络
│
⑧ VMI status 变为 Running,VM status.ready = true关机则反向:VMI 被删 → launcher Pod 退出 → 资源释放;磁盘(PVC)与定义(VM)保留。
3. 环境准备
3.1 硬件与内核要求
| 要求 | 说明 | 检查命令 |
|---|---|---|
| CPU 虚拟化扩展 | Intel VT-x / AMD-V,且宿主机开启嵌套虚拟化 | `egrep -c '(vmx |
/dev/kvm 设备 | KVM 内核模块加载后产生 | ls -l /dev/kvm |
| 内核模块 | kvm + kvm_intel/kvm_amd | `lsmod |
| K8s 版本 | ≥ 1.26(推荐 1.28+),RKE2/K3s/标准发行版均可 | kubectl version |
| 节点资源 | 每节点预留 ≥ 2C/4G 给平台组件,其余供 VM 使用 | kubectl describe node |
开启嵌套虚拟化(裸机或云主机都要确认):
bash
# Intel
echo 'options kvm_intel nested=1' > /etc/modprobe.d/kvm-nested.conf
modprobe -r kvm_intel && modprobe kvm_intel nested=1
cat /sys/module/kvm_intel/parameters/nested # 应输出 1 或 Y
# AMD
echo 'options kvm_amd nested=1' > /etc/modprobe.d/kvm-nested.conf
modprobe -r kvm_amd && modprobe kvm_amd nested=1
cat /sys/module/kvm_amd/parameters/nested⚠️ 云主机上跑 KubeVirt 属于"嵌套虚拟化",必须选用支持嵌套虚拟化的实例规格 (如阿里云 ecs.ebm 裸金属、AWS *.metal、腾讯云 裸金属),否则
/dev/kvm不存在。
3.2 节点预配置(Rocky/RHEL 系)
bash
# 1. 加载模块并持久化
modprobe kvm kvm_intel nested=1
cat > /etc/modules-load.d/kvm.conf <<'EOF'
kvm
kvm_intel
EOF
# 2. /dev/kvm 权限:让 kubelet 能把设备挂进 virt-launcher
chmod 666 /dev/kvm
# 3. RKE2 需允许特权设备(默认满足);若用 SELinux enforcing,
# 确认 kubevirt 命名空间资源可访问 /dev/kvm(或对该命名空间设 privileged 策略)3.3 网络要求
- CNI 必须支持跨节点 Pod 通信(VXLAN/IPIP 封装或真实路由)。现网踩坑: Calico 配成
ipipMode: Never, vxlanMode: Never导致跨节点 502,必须改为vxlanMode: Always(详见实战文档部署章节); - 若计划让 VM 直接使用物理网段 IP,需要 Multus + bridge/macvlan,并提前规划 宿主机网桥;
- 镜像仓库(Harbor)用于离线分发 kubevirt/CDI 镜像。
4. 安装 KubeVirt
4.1 在线安装(官方两步法)
bash
export KUBEVIRT_VERSION="v1.9.0" # 或 latest
# ① operator:CRD、RBAC、virt-operator Deployment
kubectl apply -f https://github.com/kubevirt/kubevirt/releases/download/${KUBEVIRT_VERSION}/kubevirt-operator.yaml
# ② KubeVirt CR:触发 operator 部署其余组件
kubectl apply -f https://github.com/kubevirt/kubevirt/releases/download/${KUBEVIRT_VERSION}/kubevirt-cr.yaml
# 等待部署完成
kubectl -n kubevirt wait kv kubevirt --for condition=Available --timeout=600s
kubectl get pods -n kubevirt4.2 离线/私有仓库安装(生产常用)
隔离网络环境通过内部 Harbor 代理缓存(现网方案):
镜像映射(RKE2 registries.yaml mirror):
quay.io/kubevirt/virt-operator:v1.9.0 → 192.168.122.156:30000/kubevirt/kubevirt/virt-operator:v1.9.0
quay.io/kubevirt/virt-api:v1.9.0 → .../virt-api:v1.9.0
quay.io/kubevirt/virt-controller:v1.9.0 → .../virt-controller:v1.9.0
quay.io/kubevirt/virt-handler:v1.9.0 → .../virt-handler:v1.9.0
quay.io/kubevirt/virt-launcher:v1.9.0 → .../virt-launcher:v1.9.0关键点:
kubevirt-operator.yaml中 virt-operator 的镜像地址替换为内部仓库;- KubeVirt CR 指定
imageRegistry和imageTag,operator 据此拉起其余组件:
yaml
apiVersion: kubevirt.io/v1
kind: KubeVirt
metadata:
name: kubevirt
namespace: kubevirt
spec:
imagePullPolicy: IfNotPresent
imageRegistry: 192.168.122.156:30000/kubevirt/kubevirt # 内部仓库
imageTag: v1.9.0完整离线部署记录(含故障修复)见
../rke2-kubevirt-deployment-guide.md。
4.3 KubeVirt CR 常用字段
| 字段 | 作用 |
|---|---|
spec.imageRegistry / spec.imageTag | 组件镜像源(离线必配) |
spec.imagePullPolicy | 镜像拉取策略 |
spec.configuration.developerConfiguration.featureGates | 特性开关(如 CPUManager、SRIOVLiveMigration) |
spec.configuration.network | 默认网络绑定方式等 |
spec.customizeComponents | 给组件注入补丁/注解 |
spec.workloadUpdateStrategy | 升级时如何滚动存量 VM(LiveMigrate/LiveUpdate) |
4.4 验证安装
bash
kubectl get kubevirt -n kubevirt # PHASE=Deployed
kubectl get pods -n kubevirt # 全部 Running
kubectl get crd | grep kubevirt.io # 22 个 CRD4.5 安装 virtctl 客户端
virtctl 是 VM 操作的瑞士军刀(console/vnc/migrate/expose/expand…):
bash
export VERSION=v1.9.0 ARCH=amd64
curl -Lo /usr/local/bin/virtctl \
https://github.com/kubevirt/kubevirt/releases/download/${VERSION}/virtctl-${VERSION}-linux-${ARCH}
chmod +x /usr/local/bin/virtctl
virtctl version # Client 与服务端版本应一致4.6 (可选)安装 CDI
CDI(Containerized Data Importer)提供磁盘的导入/克隆/上传能力, 是生产环境标配。安装方式与 KubeVirt 类似(operator + CR),离线环境见 ../cdi-offline-deployment-guide.md。验证:
bash
kubectl get pods -n cdi # cdi-operator/apiserver/deployment/uploadproxy Running
kubectl get cdi # PHASE=Deployed5. 第一台虚拟机
5.1 最小可运行 VM 模板
下面是一个完整注释的最小示例,使用 containerDisk(容器内嵌磁盘,适合无状态演示):
yaml
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
name: demo-vm
labels:
app: demo-vm
spec:
running: true # 创建后立即启动
template:
metadata:
labels:
app: demo-vm # Service/监控靠它选择器匹配
spec:
domain:
cpu:
cores: 2 # CPU 核数
memory:
guest: 2Gi # 客户机内存
devices:
disks:
- name: rootdisk
disk:
bus: virtio # 磁盘总线:virtio 性能最佳
- name: cloudinit
disk:
bus: virtio
interfaces:
- name: default
masquerade: {} # 默认 Pod 网络 + NAT
networks:
- name: default
pod: {} # 使用 K8s Pod 网络
volumes:
- name: rootdisk
containerDisk: # 磁盘来自容器镜像
image: quay.io/kubevirt/cirros-container-disk-demo:latest
- name: cloudinit
cloudInitNoCloud:
userData: |
#!/bin/sh
echo 'Hello KubeVirt' > /tmp/hello5.2 创建与观察
bash
kubectl apply -f demo-vm.yaml
kubectl get vm demo-vm # STATUS=Running
kubectl get vmi demo-vm # 查看运行实例与所在节点
kubectl get pods -l vm.kubevirt.io/name=demo-vm # 找到 virt-launcher Pod
kubectl describe vmi demo-vm # 事件与状态(排障首选)5.3 接入控制台
bash
virtctl console demo-vm # 串口控制台(需 VM 内有串口 tty)
virtctl vnc demo-vm # 图形控制台(本地需图形环境)
virtctl ssh root@demo-vm # 通过 virt-api 代理的 SSH
virtctl port-forward vm/demo-vm 2222:22 # 端口转发,再 ssh -p 22225.4 停止与删除
bash
virtctl stop demo-vm # 优雅关机(走 ACPI,磁盘保留)
virtctl start demo-vm # 再次启动
kubectl delete vm demo-vm # 删除 VM 定义;其 PVC 是否保留取决于磁盘类型磁盘去向:containerDisk / emptyDisk 随 VM 销毁;PVC 磁盘默认保留, 需要
kubectl delete pvc手动清理。
6. 虚拟机生命周期管理
6.1 runStrategy 五种策略(重点)
spec.running: true/false 是老写法,生产推荐用 spec.runStrategy:
| runStrategy | 行为 | 典型场景 |
|---|---|---|
| Always | 始终保持运行,崩溃/节点故障自动拉起 | 生产标配 |
| RerunOnFailure | 失败后重跑,成功后不再重启 | 批处理/一次性任务 |
| Manual | 由用户显式 start/stop,不自动干预 | 调试 |
| Halted | 等同关机,保留定义 | 长期停机 |
| Once | 运行一次,退出即结束 | 临时任务 |
yaml
spec:
runStrategy: Always设置
runStrategy时不要再写running,两者互斥。
6.2 virtctl 生命周期命令速查
| 命令 | 作用 |
|---|---|
virtctl start/stop/restart/pause/unpause <vm> | 启/停/重启/暂停/恢复 |
virtctl migrate <vm> | 触发热迁移 |
virtctl vm expand <vm> --memory/--cpu | 在线扩内存/核数(需支持) |
virtctl expose vm <vm> --port --type NodePort | 暴露服务 |
virtctl guestfs <pvc> | 用临时 Pod 挂载并修改 PVC 内磁盘 |
virtctl imageupload dv/pvc <name> -f disk.qcow2 | 本地镜像上传为 PVC |
6.3 理解状态字段
bash
kubectl get vm demo-vm -o jsonpath='{.status.printableStatus}' # Stopped/Running/...
kubectl get vm demo-vm -o jsonpath='{.status.ready}' # true=可对外提供服务
kubectl get vmi demo-vm -o jsonpath='{.status.phase}' # Pending/Scheduling/Running/Succeeded/Failed6.4 标签、注解与选择器
spec.template.metadata.labels:virt-launcher Pod、VMI、Service 选择器都依赖它, 克隆/模板化时必须改唯一,否则 Service 会误匹配;- 常用注解:
kubevirt.io/allow-pod-bridge-network-live-migration等,按需查阅文档。
第二部分 进阶篇
7. VirtualMachine Spec 概览
VM 的 YAML 分为三层,理解层次结构是进阶的关键:
VirtualMachine
├── metadata # 名称、命名空间、标签
└── spec
├── running / runStrategy # 是否运行(二选一)
├── instancetype/preference # (可选)规格与偏好引用
├── dataVolumeTemplates # (可选)随 VM 创建的磁盘模板
└── template # ★ 与 VMI 等价的部分
├── metadata.labels # launcher Pod 的标签
└── spec
├── domain # 客户机硬件:cpu/memory/firmware/clock/features/devices
│ └── devices # disks / interfaces / rng / watchdog / inputs / gpus...
├── volumes # 卷定义(PVC/containerDisk/cloudInit/...)
├── networks # 网络定义(pod / multus)
├── nodeSelector/affinity/tolerations # 调度
├── evictionStrategy # 驱逐/迁移策略
└── accessCredentials# SSH 密钥/密码注入每个字段的逐行详解见实战文档
kubevirt-practical-operations-guide.md第 2 章(虚拟机 YAML 字段详解)。
新手最容易混淆的三个对应关系:
| 关系 | 说明 |
|---|---|
domain.devices.disks[].name ↔ volumes[].name | 设备与卷通过 name 绑定,一一对应 |
domain.devices.interfaces[].name ↔ networks[].name | 网卡与网络定义通过 name 绑定 |
template.metadata.labels ↔ Service selector | Service/NodePort 靠它找到 VM |
8. 网络深入
8.1 四种典型网络拓扑
A. masquerade(默认) VM ──NAT──> Pod IP ──CNI──> 集群/外部
外部访问需经 Service/NodePort
B. bridge(Pod 网络直通) VM 直接持有 Pod IP(无 NAT)
入站直连,但受 CNI 插件限制
C. Multus 辅助网络 VM 第二网卡挂物理网桥/macvlan
→ VM 获得物理网段 IP(如 192.168.122.x),外部直连
D. SR-IOV 物理网卡 VF 直通,最高性能8.2 默认 Pod 网络(masquerade)
yaml
domain:
devices:
interfaces:
- name: default
masquerade: {} # VM 内部 10.0.2.x,NAT 借用 Pod IP
ports: # 可选:显式放行的端口(不写=全放行)
- port: 80
networks:
- name: default
pod: {}特点:
- VM 对外的源/目的都是 Pod IP,Pod IP 会随重建变化;
- 出方向默认全通;外部入站必须走 Service(ClusterIP/NodePort/LoadBalancer);
- 适合内部服务、开发测试;
- 热迁移要求 Pod 网络必须是 masquerade 绑定(bridge 绑定 Pod 网络禁止迁移)。
8.3 Multus 辅助网络(固定物理网段 IP 的核心手段)
前置:Multus + bridge/macvlan CNI 插件。核心对象是 NetworkAttachmentDefinition(NAD):
yaml
# bridge 模式:节点上先建好网桥 br-vm(把物理网卡加入网桥)
apiVersion: k8s.cni.cncf.io/v1
kind: NetworkAttachmentDefinition
metadata:
name: vm-physnet
namespace: default
spec:
config: '{
"cniVersion": "0.3.1",
"type": "bridge",
"bridge": "br-vm",
"vlan": 0,
"ipam": {}
}'VM 侧引用:
yaml
domain:
devices:
interfaces:
- name: default
masquerade: {}
- name: physnet # 第二块网卡
bridge: {} # 绑定方式:bridge(macvlan 场景同样写 bridge)
networks:
- name: default
pod: {}
- name: physnet
multus:
networkName: vm-physnet # 指向 NAD⚠️ 关键结论(现网验证):KubeVirt 的 Multus 辅助网络不会把 NAD 中 IPAM(whereabouts/host-local)分配的 IP 注入客户机。客户机内必须由 cloud-init networkData 写死静态 IP 或内部 DHCP 获取。
8.4 macvlan 模式
与 bridge 类似,只是 NAD 的 type 改为 macvlan,master 指向物理网卡, 无需在节点上建桥,但宿主机与 VM 互访受限(macvlan 特性)。
8.5 用 Multus 网络替代默认网络
把 networks 中名为 default 的网络改为 multus 引用,即可让物理网段网卡成为 VM 的唯一/主网卡(常用于"VM 必须使用固定业务网段"的强需求场景)。
9. 存储深入
9.1 KubeVirt 支持的卷类型
| 卷类型 | 数据持久性 | 典型用途 |
|---|---|---|
| persistentVolumeClaim | ✅ 持久 | 生产系统盘/数据盘(首选) |
| dataVolume | ✅ 持久 | 通过 CDI 导入/克隆/上传生成 PVC |
| containerDisk | ❌ 随 VM 销毁 | 无状态演示、金盘打包 |
| emptyDisk | ❌ 随 VM 销毁 | 临时缓存盘 |
| cloudInitNoCloud / ConfigDrive | - | 首次启动配置注入 |
| configMap / secret / serviceAccount | - | 把 K8s 资源挂进客户机 |
| hostDisk | 依赖节点 | 直接读写节点文件(谨慎使用) |
9.2 磁盘设备形态与总线
yaml
devices:
disks:
- name: rootdisk
disk:
bus: virtio # virtio(最快)/sata(兼容)/scsi
serial: DISK001 # 可选:客户机按 serial 识别磁盘
cache: none # none/writeback/writethroughdisk= 块设备;cdrom= 光驱;floppy/lun特殊用途;- 生产一律
bus: virtio,需要客户机有 virtio 驱动(现代 Linux 自带,Windows 需 virtio-win)。
9.3 PVC 作为磁盘的两种来源
手工 PV/PVC(现网早期方案,hostPath):
yaml
volumes:
- name: rootdisk
persistentVolumeClaim:
claimName: rocky9-vm2-disk # 事先创建好的 PVChostPath PV 会把数据钉死在单节点,不能迁移。生产应使用共享存储的 StorageClass 动态供应(见实战文档 NAS 存储章节)。
dataVolumeTemplates(推荐):随 VM 一起声明,CDI 自动建盘:
yaml
spec:
dataVolumeTemplates:
- metadata:
name: demo-rootdisk
spec:
source:
http:
url: "http://images.example.com/rocky9.qcow2"
pvc:
storageClassName: vm-nas
accessModes: [ReadWriteMany]
resources:
requests:
storage: 20Gi
template:
spec:
volumes:
- name: rootdisk
dataVolume:
name: demo-rootdisk9.4 CDI 的四种数据来源
| source | 说明 |
|---|---|
http/https | 从 URL 拉取 qcow2/raw/img(qcow2 会被自动转成 raw) |
registry | 从容器镜像仓库拉取磁盘镜像 |
pvc | 克隆已有 PVC(智能克隆/网络克隆) |
upload | 用 virtctl imageupload 或 cdi-uploadproxy 本地上传 |
blank | 创建空白盘 |
s3/gcs | 对象存储 |
注意:Filesystem 模式 PVC 上磁盘文件固定为
disk.img(raw), CDI 会预留 5.5% 空间开销(CDIConfig.spec.filesystemOverhead)。
10. cloud-init 与凭据注入
10.1 cloudInitNoCloud(最常用)
yaml
volumes:
- name: cloudinit
cloudInitNoCloud:
userData: |-
#cloud-config
hostname: rocky9-vm2
password: xxx
chpasswd: { expire: false }
ssh_pwauth: true
disable_root: false
users:
- name: admin
sudo: ALL=(ALL) NOPASSWD:xxx
ssh_authorized_keys:
- ssh-rsa AAAA...
networkData: |- # 静态 IP 在这里写(见实战文档)
version: 1
config:
- type: physical
name: eth1
subnets:
- type: static
address: 192.168.122.100/24
gateway: 192.168.122.1重要特性:
cloudInitNoCloud只在首次启动(无 cloud-init 实例标记)生效。 改 userData 后需删掉客户机内/var/lib/cloud/instances或重建磁盘才会重新应用。
10.2 accessCredentials(运行时可更新凭据)
比 cloud-init 更适合持续管理密钥:把 SSH 公钥放在 Secret 里,VM 通过 accessCredentials 注入,Secret 更新后 KubeVirt 会同步进客户机(需 guest agent)。
yaml
spec:
template:
spec:
accessCredentials:
- sshPublicKey:
source:
secret:
secretName: my-ssh-keys
propagationMethod:
qemuGuestAgent:
users: ["root", "admin"]11. 访问虚拟机的所有方式
| 方式 | 命令/手段 | 适用 | 特点 |
|---|---|---|---|
| 串口控制台 | virtctl console <vm> | 开机引导、网络故障抢救 | 依赖 virt-api 代理 |
| VNC 图形 | virtctl vnc <vm> | 图形界面、Windows | 本地需图形环境 |
| SSH(代理) | virtctl ssh user@<vm> | 集群内快速访问 | 走 virt-api,无需 VM 有外网 |
| 端口转发 | virtctl port-forward vm/<vm> 2222:22 | 临时调试 | 本地 2222 → VM 22 |
| Service NodePort | virtctl expose 或 YAML | 稳定外部访问(推荐) | 节点IP:端口永不变 |
| LoadBalancer/Ingress | 标准 K8s 方式 | 云上/有 LB 环境 | 四层/七层入口 |
| 物理网段直连 | Multus bridge/macvlan | 外部按固定业务 IP 直连 | 见网络章节 |
NodePort 声明式示例(生产推荐,可进 Git):
yaml
apiVersion: v1
kind: Service
metadata:
name: rocky9-vm2-ssh
spec:
type: NodePort
selector:
app: rocky9-vm2 # 与 VM template.metadata.labels 一致
ports:
- name: ssh
port: 22
targetPort: 22
nodePort: 31022 # 固定端口,双固定:节点IP+端口完整网络接入方案(含固定 IP 三选一决策)见实战文档第 3 章。
第三部分 精通篇
12. 热迁移(Live Migration)
12.1 原理与前提
热迁移 = 内存页增量复制 + 磁盘共享,客户机不断电不断网。前提:
| 条件 | 说明 |
|---|---|
| 磁盘可共享 | PVC 必须 ReadWriteMany(NFS/共享块);RWO 本地盘无法热迁移 |
| 迁移网络 | 节点间互通;可配专用迁移网络(spec.configuration.migrations.network) |
| 资源充足 | 目标节点要有等量 CPU/内存 |
| 网络模式 | Pod 网络必须 masquerade 绑定(bridge 绑定禁止迁移);固定 IP 用 Multus 第二网卡承载则不影响迁移(见实战手册 3.4) |
| 节点钉扎 | nodeSelector/亲和性钉死单节点后迁移找不到目标节点必然失败;钉节点 + 固定 Pod IP 的取舍方案见实战手册 3.5 |
| 非独占设备 | SR-IOV/GPU 直通默认不可迁移(有特性开关可部分支持) |
12.2 发起迁移
bash
virtctl migrate rocky9-vm2 # 命令行
# 或创建 VirtualMachineInstanceMigration CR(可声明目标节点/带宽限制)
kubectl get vmim # 查看迁移进度
kubectl get vm rocky9-vm2 -o wide # 迁移后观察节点变化12.3 迁移策略与调优
MigrationPolicy 可对不同 VM 分组设置带宽/并发:
yaml
apiVersion: migrations.kubevirt.io/v1alpha1
kind: MigrationPolicy
metadata:
name: low-bandwidth
spec:
bandwidthPerMigration: 64Mi
completionsTimeoutSec: 1800
selectors:
virtualMachineInstanceSelector:
workload-type: batch全局参数在 KubeVirt CR:spec.configuration.migrations (bandwidthPerMigration、parallelMigrationsPerCluster、allowAutoConverge 等)。
13. 高可用与驱逐策略
13.1 evictionStrategy
| 值 | 行为 |
|---|---|
| LiveMigrate | 节点驱逐/维护时自动热迁移(需 RWX 磁盘) |
| LiveMigrateIfPossible | 能迁就迁,不能迁就驱逐重启 |
| External | 交给外部控制器处理 |
| None | 不动(默认,节点维护会卡住) |
生产模板三件套:
yaml
spec:
template:
spec:
runStrategy 在 VM 层设 Always
evictionStrategy: LiveMigrate # 维护自动迁走
tolerations: # 节点短暂失联不急于杀 VM
- key: node.kubernetes.io/unreachable
operator: Exists
effect: NoExecute
tolerationSeconds: 600
- key: node.kubernetes.io/not-ready
operator: Exists
effect: NoExecute
tolerationSeconds: 60013.2 故障自愈链路
节点宕机
├─ 磁盘在共享存储(RWX)+ runStrategy: Always
│ → virt-controller 在其他节点重建 launcher → VM 分钟级自愈 ✅
└─ 磁盘在 local-path/单节点 hostPath
→ 数据钉死在故障节点,无法自愈 ❌(必须改造存储)现网存储 HA 加固清单见
../kubevirt-storage-ha-guide.md(挂载参数、 VM HA 声明、NAS 双控、3-2-1 备份)。
14. 快照与备份恢复
14.1 VirtualMachineSnapshot(推荐)
基于 CSI VolumeSnapshot 对磁盘做一致性快照(建议安装 qemu-guest-agent 以获得文件系统冻结):
yaml
apiVersion: snapshot.kubevirt.io/v1beta1
kind: VirtualMachineSnapshot
metadata:
name: rocky9-snap-20260903
spec:
source:
apiGroup: kubevirt.io
kind: VirtualMachine
name: rocky9-vm2bash
kubectl get virtualmachinesnapshot # PHASE=Succeeded 即成功
kubectl get virtualmachinesnapshotcontent # 快照内容(对应磁盘快照)⚠️ 要求底层 StorageClass 支持 VolumeSnapshot。NFS(subdir provisioner) 不支持快照,需使用支持快照的存储或改用备份方案(见实战文档备份章节)。
14.2 VirtualMachineRestore(从快照恢复)
yaml
apiVersion: snapshot.kubevirt.io/v1beta1
kind: VirtualMachineRestore
metadata:
name: rocky9-restore
spec:
target:
apiGroup: kubevirt.io
kind: VirtualMachine
name: rocky9-vm2 # 恢复到原 VM(也可改名恢复到新 VM)
virtualMachineSnapshotName: rocky9-snap-20260903恢复前建议先停掉目标 VM(virtctl stop)。
14.3 VirtualMachineExport(导出备份)
把 VM 磁盘导出为镜像或文件,适合跨集群迁移/异地备份:
yaml
apiVersion: export.kubevirt.io/v1beta1
kind: VirtualMachineExport
metadata:
name: rocky9-export
spec:
source:
apiGroup: kubevirt.io
kind: VirtualMachine
name: rocky9-vm2bash
virtctl export vm rocky9-vm2 --output=rocky9-backup.tar.gz14.4 备份体系分层
| 层次 | 工具 | 覆盖 |
|---|---|---|
| VM 定义 | GitOps(YAML 入库) | 配置可重建 |
| 磁盘数据 | VM Snapshot / Export / Velero | 数据可恢复 |
| 平台自身 | etcd 备份 + CRD 清单 | 集群级灾备 |
15. 克隆与黄金镜像体系
15.1 数据卷克隆(CDI)
yaml
apiVersion: cdi.kubevirt.io/v1beta1
kind: DataVolume
metadata:
name: vm001-rootdisk
spec:
source:
pvc:
namespace: default
name: golden-rocky9 # 源"金盘"
pvc:
storageClassName: vm-nas
accessModes: [ReadWriteMany]
resources:
requests:
storage: 20GiCDI 智能克隆优先走 CSI 快照(秒级),不支持时退化为网络复制。
15.2 VirtualMachineClone(整台克隆)
yaml
apiVersion: clone.kubevirt.io/v1alpha1
kind: VirtualMachineClone
metadata:
name: clone-rocky9
spec:
source:
apiGroup: kubevirt.io
kind: VirtualMachine
name: rocky9-vm2
target:
apiGroup: kubevirt.io
kind: VirtualMachine
name: rocky9-vm315.3 黄金镜像体系(生产最佳实践)
源 qcow2 → 导入一次生成金盘(DataVolume)
→ DataSource 作为版本化引用
→ 每台新 VM 从 DataSource 克隆(秒级开盘)yaml
apiVersion: cdi.kubevirt.io/v1beta1
kind: DataSource
metadata:
name: rocky9-golden
namespace: default
spec:
source:
pvc:
namespace: default
name: golden-rocky9DataVolumeTemplates 中把 source.pvc 换成 sourceRef: {kind: DataSource, name: rocky9-golden} 即可。配合 DataImportCron 可定时刷新金盘版本。
16. 监控体系
16.1 指标来源
virt-operator/api/controller/handler/launcher 均暴露 Prometheus 指标 (带 prometheus.kubevirt.io: "true" 标签)。
16.2 接入 Prometheus(kube-prometheus-stack / Rancher Monitoring)
yaml
# ServiceMonitor
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: kubevirt-metrics
namespace: monitoring
spec:
namespaceSelector:
matchNames: [kubevirt]
selector:
matchLabels:
prometheus.kubevirt.io: "true"
endpoints:
- port: metrics
scheme: https
tlsConfig:
insecureSkipVerify: true16.3 关键指标
| 指标 | 含义 | 告警建议 |
|---|---|---|
kubevirt_vmi_phase_count | 各状态 VMI 数量 | Failed > 0 |
kubevirt_vmi_memory_used_bytes | 客户机内存用量 | > 90% |
kubevirt_vmi_cpu_system_usage_seconds_total | CPU 用量 | 持续 > 80% |
kubevirt_vmi_storage_read/write_traffic_bytes | 磁盘吞吐 | 突增/为 0 |
kubevirt_migrations_in_flight | 进行中的迁移 | 卡住超时 |
kubevirt_vmi_last_migration_attempt_time | 上次迁移时间 | - |
官方提供多张 Grafana 仪表盘(带 kubevirt tag),现网已部署 4 张。
16.4 四层监控模型
第 4 层 业务层 客户机内部应用/系统 (guest agent、业务探针)
第 3 层 虚拟机层 kubevirt_vmi_*:CPU/内存/网络/磁盘/迁移 ← 现网已覆盖
第 2 层 K8s 对象层 kube-state-metrics:节点状态、Pod、requests ← 容量告警依据
第 1 层 宿主机层 node-exporter / kubelet:CPU/内存/磁盘/驱逐 ← 容量告警依据只监控第 3/4 层(VM 自身)是不够的:"宿主机资源不足"发生在第 1/2 层。 Rancher Monitoring(kube-prometheus-stack)默认已部署 node-exporter 和 kube-state-metrics,指标是现成的,关键是补上告警规则。
16.5 宿主机资源不足:两类"不足"都要监控
| 类型 | 定义 | 信号 | 后果 |
|---|---|---|---|
| A. 实际资源耗尽 | CPU/内存/磁盘真实用满 | 利用率、节点 Pressure 状态、kubelet 驱逐 | 存量 VM 变慢、OOM、被驱逐 |
| B. 调度容量耗尽 | requests 总和逼近 allocatable,新 Pod 放不下 | requests/allocatable 比值、Unschedulable Pod、VMI 卡 Scheduling | 存量无感,但新 VM 起不来、热迁移无目标节点 |
B 型最隐蔽:平时一切正常,节点故障时才发现"没有节点能接住迁移"。
关键指标
| 指标 | 来源 | 用途 |
|---|---|---|
node_cpu_seconds_total | node-exporter | CPU 利用率(按 mode) |
node_memory_MemAvailable_bytes | node-exporter | 真实可用内存(比 free 准) |
node_filesystem_avail_bytes | node-exporter | 文件系统剩余空间 |
kube_node_status_condition | kube-state-metrics | MemoryPressure/DiskPressure/PIDPressure/Ready |
kube_node_status_allocatable | kube-state-metrics | 节点可调度容量 |
kube_pod_container_resource_requests | kube-state-metrics | Pod 资源请求总量 |
kube_pod_status_unschedulable | kube-state-metrics | 无法调度的 Pod |
kubevirt_vmi_phase_count{phase=~"[Ss]cheduling"} | virt-controller | 卡在调度中的 VM |
container_memory_working_set_bytes{pod=~"virt-launcher-.*"} | cAdvisor | launcher 真实内存占用 |
推荐告警规则(PrometheusRule,可直接 apply)
yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: node-resource-rules
namespace: kubevirt
labels:
release: rancher-monitoring # ★ 必须与 Prometheus 的 ruleSelector 匹配
spec:
groups:
- name: node-resource.rules
rules:
# ---------- A 类:实际资源耗尽 ----------
- alert: NodeCPUHighUtilization
expr: (1 - avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m]))) * 100 > 85
for: 10m
labels: { severity: warning }
annotations:
summary: "节点 {{ $labels.instance }} CPU 使用率超 85%"
- alert: NodeMemoryLow
expr: node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes * 100 < 10
for: 5m
labels: { severity: critical }
annotations:
summary: "节点 {{ $labels.instance }} 可用内存不足 10%"
- alert: NodeFilesystemAlmostFull
expr: >
node_filesystem_avail_bytes{fstype!~"tmpfs|overlay|squashfs"}
/ node_filesystem_size_bytes * 100 < 15
for: 10m
labels: { severity: warning }
annotations:
summary: "节点 {{ $labels.instance }} 分区 {{ $labels.mountpoint }} 剩余 <15%"
- alert: NodeFilesystemWillFillIn24h
expr: predict_linear(node_filesystem_avail_bytes{fstype!~"tmpfs|overlay"}[6h], 24*3600) < 0
for: 30m
labels: { severity: warning }
annotations:
summary: "按当前增速,{{ $labels.mountpoint }} 24h 内写满"
- alert: NodeUnderPressure
expr: >
kube_node_status_condition{condition=~"MemoryPressure|DiskPressure|PIDPressure",status="true"} == 1
for: 2m
labels: { severity: critical }
annotations:
summary: "节点 {{ $labels.node }} 处于 {{ $labels.condition }}(接近驱逐阈值)"
- alert: NodeNotReady
expr: kube_node_status_condition{condition="Ready",status="true"} == 0
for: 5m
labels: { severity: critical }
annotations:
summary: "节点 {{ $labels.node }} NotReady"
# ---------- B 类:调度容量耗尽(KubeVirt 重点) ----------
- alert: NodeMemoryRequestsNearLimit
expr: >
sum by (node) (kube_pod_container_resource_requests{resource="memory"})
/ on(node) group_left()
kube_node_status_allocatable{resource="memory"} > 0.85
for: 10m
labels: { severity: warning }
annotations:
summary: "节点 {{ $labels.node }} 内存 requests 已达 allocatable 的 85%,新 VM 可能无法调度"
- alert: NodeCPURequestsNearLimit
expr: >
sum by (node) (kube_pod_container_resource_requests{resource="cpu"})
/ on(node) group_left()
kube_node_status_allocatable{resource="cpu"} > 0.85
for: 10m
labels: { severity: warning }
- alert: KubeVirtLauncherUnschedulable
expr: kube_pod_status_unschedulable{pod=~"virt-launcher-.*"} == 1
for: 3m
labels: { severity: critical }
annotations:
summary: "虚拟机 {{ $labels.pod }} 无法调度:没有节点装得下(资源不足的直接证据)"
- alert: KubeVirtVMISchedulingStuck
expr: kubevirt_vmi_phase_count{phase=~"[Ss]cheduling"} > 0
for: 5m
labels: { severity: warning }
annotations:
summary: "有 VMI 卡在 Scheduling 超过 5 分钟,多为节点资源不足"说明:
- kube-prometheus-stack 自带默认规则(
NodeMemoryHighUtilization、NodeFilesystemAlmostOutOfSpace、KubeNodeNotReady等)已覆盖 A 类一部分, 用kubectl get prometheusrules -A查看,按需调阈值;上面的规则重点补 **B 类(调度容量)**与 KubeVirt 专属信号;phase标签取值随版本可能是小写(现网kubevirt-rules用failed/running), 故用正则[Ss]cheduling兼容;release: rancher-monitoring标签是现网 Prometheus 发现规则的前提 (与 ServiceMonitor 同理);- 告警发出后还需在 Rancher 或 Alertmanager 中配置接收方式(钉钉/邮件/短信)。
告警发生后如何定位
bash
kubectl top nodes # 实时 CPU/内存(metrics-server)
kubectl describe node <node> | sed -n '/Allocated resources/,+12p' # requests vs allocatable
kubectl get events -A --field-selector reason=FailedScheduling # 调度失败原因
kubectl describe vmi <vm> # Events: "Insufficient memory/cpu"
kubectl get pods -A --field-selector status.phase=Pending -o wide # Pending 的 Pod16.6 KubeVirt 特有的宿主机视角观测
# 每台虚拟机在宿主机上的真实内存占用(QEMU+libvirtd)
container_memory_working_set_bytes{pod=~"virt-launcher-.*"}
# 与请求量对比:working_set 持续明显超过 requests = 超卖风险
container_memory_working_set_bytes{pod=~"virt-launcher-.*"}
/ kube_pod_container_resource_requests{resource="memory",pod=~"virt-launcher-.*"}
# 每节点 VM 密度(容量规划)
sum by (node) (kubevirt_vmi_phase_count{phase=~"[Rr]unning"})
# 发现集群里所有 kubevirt_* 指标名
group by (__name__)({__name__=~"kubevirt_.*"})16.7 预防:容量规划与水位线
| 措施 | 说明 |
|---|---|
| 预留 launcher 开销 | 每台 VM 在 memory.guest 之外,宿主机还要多耗约 256Mi~1Gi(QEMU/libvirtd/显存),规划时按 +10%~15% 计 |
| 80% 水位线 | 节点 requests 总和 ≤ 80% allocatable;利用率长期 >85% 就扩容或疏散 |
| 驱逐阈值提前告警 | kubelet 默认 memory.available<100Mi、nodefs<10%、imagefs<15% 触发驱逐;告警阈值必须设在其之前 |
| PriorityClass | VM 设较高优先级,资源紧张时优先保 VM;避免普通容器抢占 |
| ResourceQuota | 命名空间配额防止 VM 无序扩张 |
| 疏散预案 | evictionStrategy: LiveMigrate + RWX 磁盘,节点维护/告警时可 kubectl drain 自动迁走 |
| Grafana | 导入 Node Exporter Full(ID 1860);kube-prometheus-stack 自带集群/节点仪表盘 |
一句话总结:用 node-exporter/KSM 盯"节点真实水位",用 requests/allocatable 比值和"VMI 卡 Scheduling"盯"还能不能再放一台虚拟机", 两者都告警才算监控到位。
17. 性能调优
| 手段 | 配置 | 收益 | 代价 |
|---|---|---|---|
| CPU 绑核 | cpu.dedicatedCpuPlacement: true | 消除调度抖动,延迟敏感负载必备 | 该核被独占,容量下降 |
| CPU 拓扑 | cpu: {sockets, cores, threads} | 匹配客户机 NUMA/许可 | - |
| CPU 模型透传 | cpu.model: host-passthrough | 最大指令集兼容 | 热迁移仅限同构 CPU |
| 大页内存 | memory.hugepages: {pageSize: 1Gi} | 降低 TLB miss,数据库/网络负载收益大 | 节点需预留大页 |
| ioThreads | disk.dedicatedIOThread: true | 磁盘 IO 独立线程,降低延迟 | 每盘一个线程 |
| SR-IOV | interface.sriov: {} + VF 池 | 网络接近裸金属 | 需硬件/驱动支持 |
| NUMA 对齐 | numa + 节点拓扑插件 | 跨 NUMA 内存访问优化 | 配置复杂 |
NUMA/CPU 示例:
yaml
domain:
cpu:
model: host-passthrough
sockets: 1
cores: 4
threads: 1
dedicatedCpuPlacement: true
numa:
guest:
vcpu: 0
features:
- name: tsc-deadline
memory:
guest: 8Gi
hugepages:
pageSize: 1Gi开启
CPUManager特性门控(KubeVirt CRdeveloperConfiguration.featureGates) 后绑核才生效。
18. 批量管理:副本集、Pool 与 InstanceType
18.1 VirtualMachineInstanceReplicaSet
无状态 VM 批量(磁盘必须是非独占,通常配合 containerDisk):
yaml
apiVersion: kubevirt.io/v1
kind: VirtualMachineInstanceReplicaSet
metadata:
name: web-vmirs
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
domain:
cpu: { cores: 1 }
memory: { guest: 1Gi }
devices:
disks:
- name: root
disk: { bus: virtio }
volumes:
- name: root
containerDisk:
image: quay.io/kubevirt/cirros-container-disk-demo18.2 InstanceType 与 Preference
把"规格"从 VM 定义中抽离,像点菜一样选配置(类似云上选型):
yaml
apiVersion: instancetype.kubevirt.io/v1beta1
kind: VirtualMachineClusterInstancetype
metadata:
name: u1.medium
spec:
cpu:
guest: 2
memory:
guest: 4Gi
---
apiVersion: instancetype.kubevirt.io/v1beta1
kind: VirtualMachineClusterPreference
metadata:
name: linux
spec:
devices:
preferredDiskBus: virtio
preferredInterfaceModel: virtio
---
# VM 里引用
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata: { name: app-vm }
spec:
instancetype:
name: u1.medium
preference:
name: linux
template:
spec:
volumes: [...]19. 升级与版本管理
19.1 组件升级
bash
# 在线:直接 apply 新版 operator 与 CR
kubectl apply -f kubevirt-operator-new.yaml
# 离线:改 KubeVirt CR 的 imageTag,operator 滚动重建组件
kubectl -n kubevirt patch kv kubevirt --type=merge \
-p '{"spec":{"imageTag":"v1.10.0"}}'19.2 workloadUpdateStrategy(存量 VM 如何升级)
升级组件时,已在运行的 launcher 还是旧版。需要策略让它们重建:
yaml
spec:
workloadUpdateStrategy:
methods: [LiveMigrate, LiveUpdate] # 优先热迁移,不行再重启
workloadUpdateMethods: [LiveMigrate]LiveMigrate:能迁就迁,迁完旧 launcher 被新版替换(要求磁盘可共享);LiveUpdate:原地更新部分可热改的字段;- 都不满足的 VM 会保持旧版运行,需人工重启。
19.3 升级注意
- 先升级测试集群验证;
- 备份 etcd 与关键 VM 磁盘;
- 一次只升一个小版本,避免跨大版本;
- 升级后
kubectl get kv -n kubevirt确认Deployed,回归验证核心 VM。
20. 故障排查方法论
20.1 排查顺序(由外到内)
① 平台组件 kubectl get pods -n kubevirt / -n cdi 是否 Running
② 资源对象 kubectl describe vm/vmi/dv 看 Events
③ launcher Pod kubectl logs virt-launcher-<vm>-<id> qemu/libvirt 报错
④ 节点侧 journalctl -u kubelet;virt-handler 日志 设备/权限
⑤ 网络/存储 CNI 跨节点连通性;PVC Bound;挂载权限20.2 高频故障速查表
| 症状 | 常见原因 | 处理 |
|---|---|---|
VMI 卡 Scheduling | 节点无 /dev/kvm / 资源不足 | 检查嵌套虚拟化、节点余量 |
VMI Pending,Pod 不调度 | PVC 未 Bound / nodeSelector 不满足 | 查 PVC、标签 |
启动报 Permission denied | NFS root_squash / uid 映射 | 导出改 no_root_squash |
| webhook 502 | Calico 跨节点不通(无封装) | 改 vxlanMode: Always |
| console 连不上 | virt-api 未 Ready / 代理断 | 查 virt-api 副本与网络 |
| 磁盘写不进 | 权限/文件系统只读 | 查挂载选项、磁盘权限 |
| 克隆慢 | 走网络复制(无快照能力) | 换支持快照的存储 |
| 迁移失败 | 磁盘非 RWX / 资源不足 | 改共享存储 / 腾资源 |
20.3 常用排障命令
bash
kubectl describe vmi <vm> # 事件是排障第一手信息
kubectl logs -n kubevirt virt-controller-xxx # 调度/编排决策
kubectl logs virt-launcher-<vm>-xxx -c compute # qemu 真实日志
kubectl get events -n default --sort-by=.lastTimestamp
virtctl console <vm> # 进客户机看系统层附录
附录 A:术语表
| 术语 | 英文 | 说明 |
|---|---|---|
| VM | VirtualMachine | 虚拟机定义(期望状态) |
| VMI | VirtualMachineInstance | 运行中的虚拟机实例 |
| virt-launcher | - | 承载单个 VMI 的 Pod |
| CDI | Containerized Data Importer | 磁盘导入/克隆/上传组件 |
| DataVolume | DV | CDI 声明的磁盘对象 |
| 金盘 | Golden Image | 可反复克隆的母盘 |
| DataSource | - | 金盘的版本化引用 |
| NAD | NetworkAttachmentDefinition | Multus 网络定义 |
| masquerade | - | VM 借用 Pod IP 出网的 NAT 模式 |
| eviction | 驱逐 | 节点维护/故障时迁走负载 |
| live migration | 热迁移 | 不关机迁移 |
| CSI | Container Storage Interface | K8s 存储插件标准 |
| RWX | ReadWriteMany | 多节点可写(热迁移前提) |
| guest agent | QEMU Guest Agent | 客户机内代理,支持冻结/凭据注入/扩容 |
附录 B:各章复习题
入门篇
- virt-controller 与 virt-handler 的分工是什么?哪个是 DaemonSet?
- VMI 与 virt-launcher Pod 是什么关系?删除 launcher Pod 会发生什么?
runStrategy: Always与running: true有何区别?- 列出至少 3 个访问 VM 的方式。
进阶篇 5. disks[].name 与 volumes[].name 如何关联? 6. masquerade 模式下外部如何访问 VM?为什么 Pod IP 不能当固定 IP? 7. 为什么 Multus 辅助网络要配 cloud-init 静态 IP,而不是靠 NAD 的 IPAM? 8. CDI 导入 qcow2 后在 Filesystem PVC 上的文件名和格式是什么? 9. cloudInitNoCloud 为何只在首次启动生效?
精通篇 10. 热迁移对磁盘访问模式有什么硬性要求?为什么? 11. 节点宕机后,什么条件下 VM 能自动在其他节点恢复? 12. NFS(subdir provisioner)为什么不支持 VirtualMachineSnapshot?替代备份方案是什么? 13. 智能克隆何时退化为网络复制? 14. 升级组件时 workloadUpdateStrategy 的作用是什么?
附录 C:参考资料
- 官方文档: https://kubevirt.io/user-guide/
- 用户指南-网络: https://kubevirt.io/user-guide/network/
- CDI 文档: https://github.com/kubevirt/containerized-data-importer
- virtctl 参考: https://kubevirt.io/user-guide/virtctl_client/
- KubeVirt API 参考: https://kubevirt.io/api-reference/
本仓库配套文档(上一级目录):
| 文档 | 内容 |
|---|---|
kubevirt-practical-operations-guide.md | 部署实施 + 10 大运维专题(本教材的实战配套) |
../rke2-kubevirt-deployment-guide.md | RKE2 集群完整部署与故障修复记录 |
../cdi-offline-deployment-guide.md | CDI 离线部署 |
../kubevirt-nas-storage-guide.md | NAS 存储方案 |
../kubevirt-storage-ha-guide.md | 存储高可用 |
../kubevirt-network-ssh-password-guide.md | 固定 IP 与 SSH 密码管理 |
学习路径建议:先通读本教材(1~6 章上手),再跟随实战文档在真实集群完成 一次"部署 → 建盘 → 起 VM → 固定 IP → 备份 → 克隆 → 灾备演练"全流程。