Skip to content

KubeVirt 实战:部署实施与运维手册

日期: 2026-09-03 环境基线: RKE2 v1.35.6(6 节点)+ KubeVirt v1.9.0 + CDI v1.60.4,Rocky Linux 9.8,Calico VXLAN(Pod CIDR 10.22.0.0/16) 入口节点: root@192.168.122.31(sza122031.local) 镜像仓库: Harbor 192.168.122.156:30000/kubevirt/kubevirt/*(代理 quay.io/kubevirt) 配套教材: kubevirt-tutorial-beginner-to-master.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./jumpserver-in-cluster-deployment-guide.md(堡垒机接入虚拟机)


目录

  1. 部署实施
  2. 虚拟机 YAML 字段详解
  3. 网络运维专题
  4. 存储运维专题
  5. 如何将普通 KVM 转为 KubeVirt 可运行的镜像
  6. 如何备份
  7. 如何克隆
  8. 如何灾备
  9. 附录:命令速查与 FAQ

1. 部署实施

1.0 部署总览

阶段一 节点准备      → 嵌套虚拟化/设备权限/节点标签
阶段二 镜像准备      → Harbor 代理缓存 kubevirt + CDI 镜像
阶段三 KubeVirt 安装 → operator + KubeVirt CR(离线用内部仓库)
阶段四 CDI 安装      → 磁盘导入/克隆能力
阶段五 Multus 网络   → (可选)物理网段直连能力
阶段六 验证          → 组件、建盘、起 VM 全链路

1.1 阶段一:节点准备

每个将运行虚拟机的节点执行:

bash
# 1. 开启嵌套虚拟化(Intel 示例,AMD 换 kvm_amd)
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

# 2. 持久化模块
cat > /etc/modules-load.d/kvm.conf <<'EOF'
kvm
kvm_intel
EOF

# 3. 设备权限
ls -l /dev/kvm && chmod 666 /dev/kvm

# 4. (可选)给节点打标签,便于 VM nodeSelector
kubectl label node sza122031.local vm-role=true

1.2 阶段二:镜像准备(离线)

集群无法直连 quay.io,通过 Harbor 代理缓存:

# Harbor 上创建代理缓存项目:名 kubevirt,上游 quay.io/kubevirt
# RKE2 的 /etc/rancher/rke2/registries.yaml 配置 mirror 指向 Harbor

# 需要的镜像(KubeVirt v1.9.0):
virt-operator / virt-api / virt-controller / virt-handler / virt-launcher / virt-exportproxy
# CDI v1.60.4(7 个):
cdi-apiserver / cdi-cloner / cdi-controller / cdi-importer / cdi-operator / cdi-uploadproxy / cdi-uploadserver

有外网的中转机可用 skopeo 同步:

bash
for i in virt-operator virt-api virt-controller virt-handler virt-launcher; do
  skopeo copy docker://quay.io/kubevirt/${i}:v1.9.0 \
    docker://192.168.122.156:30000/kubevirt/kubevirt/${i}:v1.9.0
done

1.3 阶段三:安装 KubeVirt

bash
# ① 创建命名空间并安装 operator(离线版已把镜像替换为 Harbor 地址)
kubectl create namespace kubevirt
kubectl apply -f kubevirt-operator.yaml    # 含 22 个 CRD + RBAC + operator Deployment

# ② (现网踩坑)RBAC 不足时补充通配权限
kubectl patch clusterrole kubevirt-operator --type='json' \
  -p='[{"op":"add","path":"/rules/-","value":{"apiGroups":["*"],"resources":["*"],"verbs":["*"]}}]'

# ③ 创建 KubeVirt CR(关键:imageRegistry 指向内部仓库)
kubectl apply -f - <<'EOF'
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
EOF

# ④ 等待就绪
kubectl -n kubevirt wait kv kubevirt --for condition=Available --timeout=600s
kubectl get pods -n kubevirt     # 16 个 Pod Running

完整部署记录与故障修复见 ../rke2-kubevirt-deployment-guide.md

1.4 阶段四:安装 CDI(磁盘导入/克隆能力)

隔离环境采用运行时导出的单文件清单(51 个对象),详见 ../cdi-offline-deployment-guide.md

bash
kubectl apply -f cdi-deploy.yaml          # 与官方 operator+cr 二选一
kubectl -n cdi wait cdi cdi --for condition=Available --timeout=300s
kubectl get pods -n cdi

关键 CDI 配置(CDI CR 内):

yaml
spec:
  config:
    honorWaitForFirstConsumer: true   # 等 VM 调度后再导入,避免导入到错误节点
  # 默认文件系统开销 5.5%

1.5 阶段五:安装 Multus(可选,物理网段直连需要)

bash
kubectl get pods -n kube-system | grep multus          # RKE2 通常自带
kubectl get crd network-attachment-definitions.k8s.cni.cncf.io

# 缺失时用 Helm 安装
helm repo add rke2-charts https://rancher.github.io/rke2-charts
helm install multus rke2-charts/rke2-multus -n kube-system

# bridge 模式还需在每个节点部署 bridge CNI 插件(/opt/cni/bin/bridge)

1.6 阶段六:部署验证清单

bash
# 平台组件
kubectl get kubevirt -n kubevirt                 # PHASE=Deployed
kubectl get cdi                                  # PHASE=Deployed
kubectl get pods -n kubevirt -n cdi              # 全 Running

# 存储
kubectl get storageclass                          # 有可用的共享存储 SC(如 vm-nas)

# 端到端:导入镜像 → 起 VM → 网络可达
# (流程见 4.1 NAS 存储章节与教材第 5 章)

1.7 部署常见问题(现网实测)

问题现象解决
operator RBAC 不足日志 forbidden见 1.3 步骤②
Calico 跨节点不通webhook 502IPPool 改 vxlanMode: Always,重启 calico-node
virt-handler 证书缺失handler 起不来重新触发部署/运行修复脚本
/dev/kvm 不存在VMI 卡 Scheduling开嵌套虚拟化(1.1)
CDI CRD 存根干扰创建 DV 报错清理旧 CRD 后重装

2. 虚拟机 YAML 字段详解

2.1 生产级完整示例(逐行注释)

以下 YAML 汇总了生产环境最常用的字段(NAS 存储 + 固定 IP + HA):

yaml
apiVersion: kubevirt.io/v1          # KubeVirt API 组,v1 为稳定版
kind: VirtualMachine                # 虚拟机定义(长期存在,可反复启停)
metadata:
  name: rocky9-vm2                  # VM 名称(也是默认 VMI/launcher 名前缀)
  namespace: default                # 命名空间
  labels:                           # VM 对象标签,用于检索/分组
    app: rocky9-vm2
    kubevirt.io/vm: rocky9-vm2
spec:
  running: true                     # 期望运行状态(与 runStrategy 二选一)
  # runStrategy: Always             # 生产推荐:崩溃/节点故障自动拉起
  template:                         # ★ VMI 模板,结构与 Pod spec 类似
    metadata:
      labels:                       # ★ launcher Pod/VMI 的标签
        app: rocky9-vm2             #   Service selector 必须匹配这里
        kubevirt.io/vm: rocky9-vm2
    spec:
      evictionStrategy: LiveMigrate # 节点维护/驱逐时热迁移(需 RWX 磁盘)
      terminationGracePeriodSeconds: 60   # 优雅关机等待秒数
      nodeSelector:                 # 调度:限定节点(可选)
        kubernetes.io/hostname: sza122031.local
      tolerations:                  # 容忍节点污点(短暂失联不急于杀 VM)
      - key: node.kubernetes.io/unreachable
        operator: Exists
        effect: NoExecute
        tolerationSeconds: 600
      domain:                       # ★★★ 客户机硬件定义(对应 libvirt domain)
        cpu:
          cores: 2                  # vCPU 核数(也可用 sockets/threads 描述拓扑)
          # model: host-passthrough # 透传宿主 CPU 特性(热迁移需同构)
          # dedicatedCpuPlacement: true   # 独占物理核(性能敏感场景)
        memory:
          guest: 2Gi                # 客户机内存
          # hugepages: { pageSize: 1Gi }  # 大页(需节点预留)
        machine:
          type: q35                 # 机型:q35(推荐)/ pc / 可指定版本
        firmware:
          # bootMenu: { enabled: true }   # 开机启动菜单(调试用)
          # bootloader: { efi: { secureBoot: false } }  # UEFI 启动(按需)
        clock:
          utc: {}                   # 时钟源:utc(Linux)/ timezone
          timer:
            hpet: { present: false }
            hyperv: {}              # Windows 需要
            kvm: {}
            pit: { tickPolicy: delay }
            rtc: { tickPolicy: catchup }
        features:
          acpi: {}                  # 电源管理(关机靠它)
          smm: { enabled: true }    # 安全模式(UEFI SecureBoot 需要)
        devices:                    # ★ 设备列表
          disks:                    # 磁盘设备
          - name: rootdisk          # ★ 与 volumes[].name 对应
            disk:
              bus: virtio           # virtio(最快)/sata/scsi
            cache: none             # none/writeback/writethrough
            # serial: DISK001       # 磁盘序列号(客户机识别用)
          - name: cloudinit
            disk:
              bus: virtio
          interfaces:               # 网卡设备
          - name: default           # ★ 与 networks[].name 对应
            masquerade: {}          # 绑定方式:masquerade(NAT 借用 Pod IP)
            # bridge: {}            # 或 bridge(直通,配合 Multus)
            # sriov: {}             # 或 SR-IOV 直通
            model: virtio           # 网卡型号:virtio(推荐)/e1000e
            # macAddress: de:00:00:00:00:01   # 固定 MAC(可选)
          # 其他可选设备:
          # rng: {}                 # 随机数设备
          # watchdog: { name: w1, i6300esb: {} }  # 看门狗
          # inputs:                 # 输入设备(VNC 鼠标用 tablet 更准)
          # - { type: tablet, bus: virtio, name: tablet }
          # autoattachPodInterface: true     # 自动挂 Pod 网络(默认)
          # autoattachGraphicsDevice: true   # 自动挂显卡(VNC 用)
      networks:                     # ★ 网络定义(与 interfaces 对应)
      - name: default
        pod: {}                     # 使用 K8s Pod 网络
      # - name: physnet             # Multus 辅助网络示例
      #   multus:
      #     networkName: vm-physnet # 指向 NetworkAttachmentDefinition
      volumes:                      # ★ 卷定义(与 disks 对应)
      - name: rootdisk
        persistentVolumeClaim:
          claimName: rocky9-vm2-disk    # 已存在的 PVC
        # dataVolume: { name: xxx }     # 或用 CDI DataVolume
        # containerDisk: { image: ... } # 或容器内嵌磁盘(无状态)
      - name: cloudinit
        cloudInitNoCloud:
          userData: |-              # 首次启动配置(主机名/密码/SSH)
            #cloud-config
            hostname: rocky9-vm2
            password: xxx
            chpasswd: { expire: false }
            ssh_pwauth: true
            disable_root: false
          networkData: |-           # 静态 IP 配置(见 3.1)
            version: 1
            config:
            - type: physical
              name: eth1
              subnets:
              - type: static
                address: 192.168.122.100/24
                gateway: 192.168.122.1

2.2 字段分组速查表

顶层与调度

字段类型说明常用值
spec.runningbool期望运行状态true/false(与 runStrategy 二选一)
spec.runStrategystring运行策略Always(生产)/Manual/Halted/RerunOnFailure/Once
spec.instancetyperef规格引用抽离 CPU/内存
spec.dataVolumeTemplates[]随 VM 建盘见教材 9.3
template.spec.nodeSelectormap限定节点kubernetes.io/hostname: xxx
template.spec.affinityobj复杂调度/反亲和多 VM 分散
template.spec.tolerations[]容忍污点节点失联延迟杀
template.spec.evictionStrategystring驱逐策略LiveMigrate(推荐)/None
template.spec.terminationGracePeriodSecondsint关机宽限60

domain.cpu / memory / machine / firmware

字段说明备注
cpu.coresvCPU 核数扩容改这里
cpu.sockets/threadsCPU 拓扑配合许可证/NUMA
cpu.modelCPU 型号host-passthrough/host-model/指定型号
cpu.dedicatedCpuPlacement绑核需 CPUManager 特性
cpu.numaNUMA 拓扑大内存性能
memory.guest客户机内存扩容改这里
memory.hugepages大页需节点预留
machine.type机型q35 推荐
firmware.serial序列号唯一标识
firmware.bootloader.efiUEFI 启动SecureBoot 可选
firmware.bootMenu启动菜单调试用

domain.devices

字段说明备注
disks[].name设备名必须匹配 volumes[].name
disks[].disk.bus总线virtio/sata/scsi
disks[].cdrom光驱挂 ISO
disks[].cache缓存模式none 安全
disks[].dedicatedIOThread独立 IO 线程低延迟
disks[].serial序列号客户机识别
interfaces[].name网卡名必须匹配 networks[].name
interfaces[].masqueradeNAT 绑定借 Pod IP
interfaces[].bridge桥接绑定配合 Multus
interfaces[].sriovSR-IOV高性能
interfaces[].model型号virtio/e1000e
interfaces[].macAddress固定 MAC可选
interfaces[].ports放行端口masquerade 下有效
rng随机数设备建议加
watchdog看门狗客户机挂死重启
inputs键鼠/平板VNC 交互
gpus / hostDevicesGPU/设备直通需硬件支持
tpm可信平台Windows 11 需要

volumes(与 disks 一一对应)

卷类型字段持久性用途
持久卷persistentVolumeClaim.claimName生产首选
CDI 盘dataVolume.name导入/克隆生成
容器盘containerDisk.image无状态演示
临时盘emptyDisk.capacity缓存
cloud-initcloudInitNoCloud-首次配置
配置盘configMap/secret/serviceAccount-挂资源进客户机
主机盘hostDisk节点相关谨慎

networks(与 interfaces 一一对应)

字段说明
pod: {}K8s Pod 网络(默认)
multus.networkNameMultus 网络(指向 NAD)

完整字段清单以官方 API 参考为准:https://kubevirt.io/api-reference/


3. 网络运维专题

先建立一张"网络模式决策表",后面所有操作都围绕它展开:

模式VM 拿到的 IP谁能直连固定性适用
masquerade(默认)借用 Pod IP(NAT)仅集群内❌ 重建即变内部服务
Pod 网络 bridge自己的 Pod IP集群内❌ 随 Pod 变集群内直连
Multus bridge/macvlan物理网段固定 IP外部直连✅ 写死静态外部按业务 IP 直连
Service NodePort节点 IP:端口外部✅ 端口固定稳定入口

3.1 静态 IP 如何配置

核心结论(现网验证):KubeVirt 不会把 Multus NAD 中 IPAM 分配的 IP 注入客户机。 要给 VM 固定静态 IP,标准做法是 cloud-init networkData 在客户机内写死。 共 5 步。

步骤 ①:确认 Multus 已就绪

bash
kubectl get pods -n kube-system | grep multus
kubectl get crd network-attachment-definitions.k8s.cni.cncf.io

步骤 ②:(bridge 模式)节点上建网桥

把物理网卡加入网桥 br-vm,让 VM 流量直接进物理网络:

bash
# 以 nmcli 为例(Rocky 9)
nmcli con add type bridge ifname br-vm
nmcli con add type bridge-slave ifname eth1 master br-vm   # eth1=上联网卡
nmcli con down eth1 && nmcli con up br-vm
ip addr show br-vm      # 确认网桥拿到原网卡 IP

⚠️ 若节点只有一个上联网卡,建桥会导致短暂断网,务必带外(IPMI/控制台)操作。

步骤 ③:创建 NetworkAttachmentDefinition

yaml
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",
    "ipam": {}
  }'
bash
kubectl apply -f nad.yaml
kubectl get net-attach-def            # 确认出现

步骤 ④:VM 增加第二块网卡引用 NAD

yaml
domain:
  devices:
    interfaces:
    - name: default
      masquerade: {}          # 保留默认网络(可选,用于集群内通信/SSH 兜底)
    - name: physnet
      bridge: {}              # 绑到网桥
      model: virtio
networks:
- name: default
  pod: {}
- name: physnet
  multus:
    networkName: vm-physnet   # ★ 指向 NAD

步骤 ⑤:cloud-init 写死静态 IP

yaml
volumes:
- name: cloudinit
  cloudInitNoCloud:
    networkData: |-
      version: 1
      config:
      - type: physical
        name: eth1                 # 第二块网卡在客户机内的名称
        subnets:
        - type: static
          address: 192.168.122.100/24
          gateway: 192.168.122.1
          dns_nameservers: [223.5.5.5]

网卡名需与客户机一致。不确定时先起 VM 用 ip a 看 MAC/名称,再回填。 改 networkData 后,需清除客户机 /var/lib/cloud/instances 或重建磁盘才重新应用。

验证

bash
kubectl get vmi rocky9-vm2 -o jsonpath='{.status.interfaces}'   # 平台视角
# 从外部机器
ping 192.168.122.100 && ssh root@192.168.122.100

3.2 配置为 Pod IP 还是节点 IP

这是"VM 对外的身份"选择题。两种含义要分清:

(A) 让 VM 用 Pod IP(集群内访问)

默认 masquerade 即是。VM 出网源 = Pod IP(10.22.x.x),集群内可直接访问, 但 Pod IP 不稳定,外部不可直连。适合纯内部服务。

yaml
interfaces:
- name: default
  masquerade: {}
networks:
- name: default
  pod: {}

集群内访问:kubectl get vmi <vm> -o jsonpath='{.status.interfaces[0].ipAddress}'

(B) 让 VM 走"节点侧入口"(对外访问)

这里有两种不同含义,按需选:

B-1:节点 IP + 端口(NodePort,零节点改造,推荐起步)

VM 仍在 Pod 网络,但通过 Service 在每个节点的固定端口暴露, 外部用 节点IP:端口 访问,永远不变:

yaml
apiVersion: v1
kind: Service
metadata:
  name: rocky9-vm2-ssh
spec:
  type: NodePort
  selector:
    app: rocky9-vm2          # 匹配 VM template.labels
  ports:
  - name: ssh
    port: 22
    targetPort: 22
    nodePort: 31022          # 固定端口(30000-32767)
bash
kubectl apply -f svc.yaml
ssh root@192.168.122.31 -p 31022     # 任意节点 IP 都可

特点:外部看到的源是节点(NAT),VM 内感知不到真实客户端 IP。 适合"只要稳定连上",不想动节点网络的场景。

B-2:节点物理网段固定 IP(Multus bridge,外部真直连)

即 3.1 的方案。VM 拥有物理网段 IP(如 192.168.122.100),外部按业务 IP 直连, 无 NAT。适合外部系统必须按固定业务 IP 访问的场景。

选型速记

只要稳定访问、不想改节点网络 → B-1 NodePort(10 分钟搞定)
外部必须按物理网段固定 IP 直连 → B-2 Multus bridge(5 步)
纯集群内部服务              → A  masquerade

完整三方案对比与踩坑见 ../kubevirt-network-ssh-password-guide.md

3.3 如何修改网络网段

"改网段"分三种情况,风险从低到高,先判断自己属于哪一种:

情况改什么影响面风险
① VM 静态 IP 网段cloud-init 的 address/gateway单台 VM
② Multus 网桥网段节点网桥 + NAD + 静态 IP该网桥所有 VM
③ Pod 网络网段(Calico CIDR)IPPool + 可能动 API Server整个集群高(谨慎)

① 改单台 VM 的静态 IP 网段(最常见、最安全)

适用:物理网络规划变了,或把 VM 挪到新网段。

bash
# 1. 编辑 VM 的 cloud-init networkData
kubectl edit vm rocky9-vm2
#    修改 address: 新网段/掩码、gateway、dns

# 2. 让 cloud-init 重新生效:清客户机实例标记后重启
virtctl stop rocky9-vm2
# (可选)进盘清理 /var/lib/cloud/instances,或直接重建网络配置
virtctl start rocky9-vm2

若 VM 里已经手工配过网络(cloud-init 不再管),则直接进客户机改 /etc/NetworkManager/system-connections/nmcli,无需动 YAML。

② 改 Multus 网桥对应的网段

网段由物理网络决定(网桥挂在哪个 VLAN/上联),改网段本质是改节点网桥的 上联和 IP 规划:

bash
# 1. 停掉该网桥上所有 VM
# 2. 调整节点网桥上联(换 VLAN 口 / 改 IP)
nmcli con mod br-vm ipv4.addresses 新网段/掩码 ...
# 3. 更新 NAD(若涉及 VLAN 号)
kubectl edit net-attach-def vm-physnet
# 4. 逐台改 VM 静态 IP(回到情况①)并验证

③ 改 Pod 网络网段(Calico CIDR)——高危

强烈建议:生产集群尽量不要在线改 Pod CIDR,能新建集群就不改存量。 若必须改,要点如下:

bash
# 1. 备份 etcd 与全部 IPPool 定义
kubectl get ippool -o yaml > ippool-backup.yaml

# 2. 新建目标网段的 IPPool(不要直接改旧池,先并存)
kubectl apply -f - <<'EOF'
apiVersion: crd.projectcalico.org/v1
kind: IPPool
metadata:
  name: new-ipv4-ippool
spec:
  cidr: 10.33.0.0/16          # 新网段
  blockSize: 26
  ipipMode: Never
  vxlanMode: Always            # ★ 与现网一致,保持封装
  natOutgoing: true
  nodeSelector: all()
EOF

# 3. 把旧池设为不再分配新 IP(禁用而非删除,避免存量 Pod 失联)
kubectl patch ippool default-ipv4-ippool --type=merge \
  -p '{"spec":{"disabled":true}}'

# 4. 滚动重启工作负载,让 Pod 逐步用新池;确认无异常后
#    再删除旧池(务必确认没有 Pod 还在用旧段)

⚠️ 现网踩坑记录(误删 ippools CRD 导致全网断网)见 ../rke2-kubevirt-deployment-guide.md §5.2。改 Pod CIDR 前必须演练 + 备份 + 回滚预案。 改 CIDR 会影响 Service、CNI、API Server 关联配置,务必评估全部依赖。

网段修改检查清单

  • [ ] 明确属于①②③哪一种,从低风险开始
  • [ ] 已备份相关对象(VM YAML / IPPool / NAD)
  • [ ] 物理网络(网关、VLAN、路由)已同步调整
  • [ ] 逐台验证连通性后再批量
  • [ ] 更新文档与监控里记录的网段信息

3.4 固定 IP 与热迁移共存

关键认知

热迁移不依赖任何固定 IP:迁移通道走的是 Pod 网络(masquerade),Pod IP 在目标节点重建时变化是正常现象,不影响迁移。官方硬性约束(Live Migration 文档):

  • Pod 网络必须 masquerade 绑定——bridge 绑定 Pod 网络禁止热迁移
  • 磁盘 PVC 必须 ReadWriteMany
  • virt-launcher 需要 49152/49153 端口可用(masquerade 接口不要显式占用)。

所以正确思路不是"固定 Pod IP",而是:Pod IP 随它变,另加一块网卡专门承载 固定 IP(双网卡架构)

方案对比

#方案固定 IP 方式迁移后 IP适用场景备注
1Multus bridge 第二网卡 + cloud-init networkData 静态 IP(推荐)客户机内写死✅ 不变(写在客户机配置里)外部系统需按物理网段固定 IP 直连所有候选节点都要建好同名网桥、同 L2
2Multus 第二网卡 + whereabouts IPAM集群级 IPAM 自动分配⚠️ 网络侧 IP 由 IPAM 预留保持,但现网验证 IPAM 分配的 IP 不会注入客户机,客户机仍需静态配置,效果等同方案 1希望集中管理地址池多引入组件,现网直接用方案 1 即可
3固定 VMI macAddress + DHCP 服务器 MAC 预留客户机 DHCP 获得预留固定 IP✅ 不变物理网段有 DHCP 服务器、希望集中管理VM spec 需指定 interfaces[].macAddress
4Service/NodePort(或 MetalLB LoadBalancer)入口固定:节点IP:端口 或 VIP✅ 入口不变(Pod IP 随便变)访问稳定即可,不必把固定 IP 放进客户机改造最小,迁移完全透明
5passt 绑定(v1.8+ 新)客户机直接持有 Pod IP✅ 官方:客户机保留原 IP 直至 DHCP 续租单网卡简化场景Beta、不支持辅助网络、额外 +250Mi 内存

推荐架构(方案 1)

                     ┌─ eth0(masquerade,Pod IP 会变)──> KubeVirt 控制面 / 热迁移通道
VM(rocky9-vm2)─────┤
                     └─ eth1(Multus bridge br-vm)──────> 192.168.122.102 固定,物理网段直达
  • eth0:保留默认 pod: {} + masquerade: {}——热迁移数据通道,绝不能去掉 (现网排障记录:双网卡后无法热迁移,原因就是丢了默认 pod: {} 网络);
  • eth1multus + bridge: {} 挂物理网桥,IP 由 networkData 写死。 完整 YAML 见 ../kubevirt-network-ssh-password-guide.md 第 6 章(rocky9-vm2 实例)。

前提与注意事项

  1. 磁盘为 RWX 共享存储(NFS vm-nas)——热迁移本身的前提;
  2. 所有候选节点上存在同一 NAD、建好同名网桥(br-vm),桥成员接入同一 物理网络 / L2 域;任一节点缺桥,迁移到该节点会失败;
  3. 不要用 nodeSelector 把 VM 钉死在特定节点(否则迁移没有意义);
  4. 切换后客户机发送 Gratuitous ARP 刷新交换机 MAC 表(标准内核自动完成), 秒级丢包属正常现象;
  5. 不要用 host-local IPAM:地址池按节点本地分配,跨节点迁移后 IP 必变。

验证

bash
virtctl migrate rocky9-vm2 && kubectl get vmim -w
# 迁移完成后:
kubectl get vm rocky9-vm2 -o wide        # 观察 NODE 已切换
ping -c 3 192.168.122.102                # 固定 IP 仍可达
ssh root@192.168.122.102                 # 业务连接不中断

3.5 钉节点 + 固定 Pod IP(放弃热迁移场景)

结论:能做,三个环节都有官方支持

需求手段依据(已在源码核实)
固定 Pod IPCalico 注解 cni.projectcalico.org/ipAddrsCalico CNI 的 k8s.go 直接解析该注解,向 calico-ipam 申请指定 IP(RKE2 默认即 calico-ipam,无需 feature gate
注解放到 launcher PodVM spec.template.metadata.annotationsKubeVirt filterVMIAnnotationsForPod 把 VMI 注解原样复制到 virt-launcher Pod(仅过滤 kubectl.kubernetes.io* 等 3 个前缀)
钉节点spec.template.spec.nodeSelector标准 K8s 放置能力
放弃热迁移没有显式开关,也不需要:钉死后迁移找不到目标节点必然失败;可再叠加 RWO 本地盘双重封死

完整 YAML

yaml
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: rocky9-static
spec:
  running: true
  template:
    metadata:
      annotations:
        # Calico 申请固定 Pod IP:须在 Pod CIDR 10.22.0.0/16 内、未被其他 Pod 占用
        cni.projectcalico.org/ipAddrs: '["10.22.100.10"]'
    spec:
      nodeSelector:
        kubernetes.io/hostname: rke2-worker-3        # ★ 钉到固定节点
      domain:
        devices:
          interfaces:
          - name: default
            masquerade: {}
        resources:
          requests: { memory: 2Gi }
      networks:
      - name: default
        pod: {}

💡 钉节点后不再依赖共享存储,磁盘可改用本地盘 RWO(无需 NFS), 这反过来又天然阻断了热迁移——两件事互相加强。

IP 稳定性矩阵(什么情况下变、什么情况下不变)

事件Pod IP
容器重启 / kubelet 或节点重启(Pod 对象还在)✅ 不变
virtctl restart / 客户机内重启(重建 launcher Pod)✅ 不变——新 Pod 仍声明同一地址,旧地址已释放,Calico 原样再分配
手动删除 virt-launcher Pod✅ 不变(同上)
钉住的节点宕机❌ Pod 无法调度到别处,VM 中断到节点恢复——这就是"放弃迁移"的代价

防 IP 冲突约定

动态分配按需借 /26 块、从低地址开始,因此把固定 Pod IP 集中规划在高位段 (如 10.22.100.0/24)并维护一张登记表(哪台 VM 用哪个 IP),实际冲突概率极低。 分配前也可先确认:

bash
kubectl get workloadendpoints -A | grep 10.22.100.10 || echo "未占用"

验证

bash
kubectl apply -f rocky9-static.yaml
kubectl get vmi rocky9-static -o wide
# launcher Pod 的 IP 应等于 10.22.100.10:
kubectl get pods -l vm.kubevirt.io/name=rocky9-static -o wide
kubectl get pod -l vm.kubevirt.io/name=rocky9-static \
  -o jsonpath='{.items[0].metadata.annotations.cni\.projectcalico\.org/ipAddrs}'

# 节点上直连(Pod IP 只在集群内路由):
ping -c 2 10.22.100.10

# 确认迁移已被"事实封死":
virtctl migrate rocky9-static        # 应失败:找不到合格目标节点

与其他固定 IP 手段的定位对比

手段可达范围兼容热迁移适用
本节:固定 Pod IP + 钉节点仅集群内(出方向带 SNAT)集群内白名单/互访场景,零额外组件
3.4:Multus 物理网段固定 IP物理网段直达对外固定入口(推荐)
Service ClusterIP/NodePort入口级固定服务化暴露

4. 存储运维专题

4.1 如何使用 NAS 做存储

原理:KubeVirt 虚拟机磁盘本质是一个 PVC。任何能供应 PVC 的存储后端 (NFS / iSCSI / 厂商 CSI)都可以。商用 NAS 最常用 NFS

三种接入方式对比

方式适用优点限制
NFS(推荐起步)所有商用 NAS通用、天然 RWX、支持热迁移延迟高于块存储
厂商 CSI(Trident/Synology/华为等)中高端 NAS快照/在线扩容/精简配置需装厂商组件
iSCSIIOPS/延迟敏感块级性能最好RWO 单挂载,不能热迁移

落地四步

步骤 ①:NAS 侧创建 NFS 导出

导出目录:/exports/kubevirt
选项:    rw, sync, no_root_squash, no_subtree_check

⚠️ no_root_squash 很关键:virt-launcher 内 qemu 以非 root(uid 107)运行, 若开了 root_squash 会导致磁盘写 Permission denied

步骤 ②:部署 nfs-subdir-external-provisioner 指向 NAS

yaml
env:
  - name: NFS_SERVER
    value: "<NAS IP>"
  - name: NFS_PATH
    value: "/exports/kubevirt"

步骤 ③:创建专用 StorageClass

yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: vm-nas
provisioner: cluster.local/nfs-subdir-external-provisioner
reclaimPolicy: Retain          # VM 盘建议 Retain 防误删
allowVolumeExpansion: true     # ★ 允许扩容(4.2 用到)
mountOptions:
  - nfsvers=4.1
  - hard                       # ★ NAS 故障时 IO 挂起等待,恢复后自愈
  - timeo=600
  - retrans=5
  - noatime

步骤 ④:验证

bash
# 各节点手动挂载
mount -t nfs4 <NAS IP>:/exports/kubevirt /mnt/t && touch /mnt/t/x && rm /mnt/t/x
# PVC 秒级 Bound、写文件无 Permission denied

用 NAS 起一台 VM(完整链路)

NAS 上放 qcow2 镜像 → 用 HTTP 暴露 → CDI DataVolume 导入(qcow2 自动转 raw)
→ 生成 PVC → VM 从该 PVC 启动
yaml
# DataVolume 导入示例
apiVersion: cdi.kubevirt.io/v1beta1
kind: DataVolume
metadata:
  name: vm001-rootdisk
spec:
  source:
    http:
      url: "http://<NAS或文件服务器>/images/rocky9.qcow2"
  pvc:
    storageClassName: vm-nas
    accessModes: [ReadWriteMany]   # ★ 需要热迁移用 RWX
    resources:
      requests:
        storage: 20Gi
bash
kubectl get dv vm001-rootdisk        # PHASE=Succeeded 即导入完成

⚠️ 注意:CDI 不支持 nfs:// 直接导入,NAS 上的 qcow2 需先用 HTTP 暴露。 导入产物在 Filesystem PVC 上固定为 disk.img(raw)。 更多容量规划、IOPS 估算见 ../kubevirt-nas-storage-guide.md

4.2 如何扩容资源(CPU/内存/磁盘)

扩容分两类:计算资源(CPU/内存)和磁盘。改法不同。

(A) 扩 CPU / 内存

方式一:在线扩(需客户机支持热插)

bash
virtctl vm expand rocky9-vm2 --memory 4Gi --cpu 4

方式二:改 YAML 后重启(最通用、最稳)

bash
kubectl edit vm rocky9-vm2
# 修改 spec.template.spec.domain.cpu.cores
# 修改 spec.template.spec.domain.memory.guest
kubectl apply -f rocky9-vm2.yaml
virtctl restart rocky9-vm2          # 生效需重启

说明:domain 属于"硬件规格",多数字段改了要重启才能生效。 扩内存注意节点余量;绑核(dedicatedCpuPlacement)场景扩容受节点物理核限制。

(B) 扩磁盘

前提:StorageClass 已 allowVolumeExpansion: true(见 4.1 步骤③)。

bash
# 1. 扩大 PVC
kubectl patch pvc vm001-rootdisk -p \
  '{"spec":{"resources":{"requests":{"storage":"40Gi"}}}}'
# 或 kubectl edit pvc vm001-rootdisk

# 2. 等文件系统层扩容完成
kubectl get pvc vm001-rootdisk -o jsonpath='{.status.capacity.storage}'

进客户机扩文件系统(关键,PVC 扩容不会自动扩客户机内文件系统):

bash
# 在客户机内
growpart /dev/vda 1                 # 扩分区(若是整盘则跳过)
# ext4:
resize2fs /dev/vda1
# xfs:
xfs_growfs /
df -h                               # 确认容量生效

⚠️ NFS 盘扩容本质是"允许写更大",无真实容量校验;但为一致性与 配额管理,仍应走 PVC 扩容流程并同步改客户机文件系统。 缩容(减小磁盘)风险极高,不建议在线做,需备份后重建。

扩容检查清单

  • [ ] 节点有足够 CPU/内存余量(计算扩容)
  • [ ] StorageClass allowVolumeExpansion: true(磁盘扩容)
  • [ ] 磁盘扩容后进客户机执行了 growpart + resize2fs/xfs_growfs
  • [ ] 扩容后监控确认容量/性能正常

5. 如何将普通 KVM 转为 KubeVirt 可运行的镜像

把现有 libvirt/KVM 虚拟机搬上 KubeVirt,核心是"导出一块干净的磁盘镜像 → 导入为 PVC → 用 VM 引用"。完整流程如下。

5.1 流程总览

① 源 KVM 关机、导出磁盘(qcow2)
② 清理镜像(主机名/网络/SSH host key,避免克隆冲突)
③ (可选)压缩/瘦身
④ 暴露为 HTTP 或上传
⑤ CDI DataVolume 导入为 PVC
⑥ 创建 VM 引用该 PVC,验证启动

5.2 步骤①:导出源磁盘

bash
# 源 KVM 宿主机
virsh list --all                          # 找到目标域名
virsh shutdown <domain>                   # 优雅关机(保证磁盘一致性)
virsh domblklist <domain>                 # 查磁盘路径,如 /var/lib/libvirt/images/vm.qcow2
qemu-img info /var/lib/libvirt/images/vm.qcow2   # 确认格式与虚拟大小

5.3 步骤②:清理镜像(关键,避免"克隆后遗症")

直接复制的镜像带有源机的主机名、SSH host key、固定网卡配置,批量使用会冲突。 用 virt-sysprep 清理:

bash
dnf install -y libguestfs-tools
virt-sysprep -a vm.qcow2 \
  --operations machine-id,ssh-hostkeys,udev-net-addr,net-hostname,logfiles,tmp-files

如果源机网络是写死的静态配置,而目标要走 DHCP/masquerade, 还需要清掉固定网卡配置(或用 virt-customize --run-command 改回 DHCP)。

5.4 步骤③:瘦身(可选,减小导入体积)

bash
virt-sparsify --compress vm.qcow2 vm-clean.qcow2
qemu-img info vm-clean.qcow2      # 确认实际占用变小

5.5 步骤④:暴露镜像供 CDI 拉取

CDI 支持 http/httpsregistryupload 等。内网最常用 HTTP:

bash
# 把镜像放到任意 HTTP 服务(Nginx/文件服务器)
# 现网示例:http://192.168.122.9:9001/repo/osiso/

5.6 步骤⑤:DataVolume 导入为 PVC

yaml
apiVersion: cdi.kubevirt.io/v1beta1
kind: DataVolume
metadata:
  name: migrated-vm-rootdisk
  namespace: default
spec:
  source:
    http:
      url: "http://192.168.122.9:9001/repo/osiso/vm-clean.qcow2"
  pvc:
    storageClassName: vm-nas        # 用共享存储,方便迁移
    accessModes: [ReadWriteMany]
    resources:
      requests:
        storage: 40Gi               # ≥ 源磁盘虚拟大小
bash
kubectl apply -f dv.yaml
kubectl get dv migrated-vm-rootdisk      # 等到 PHASE=Succeeded

本地文件不想走 HTTP 时,可直接上传: virtctl imageupload dv migrated-vm-rootdisk --image-path vm-clean.qcow2

5.7 步骤⑥:创建 VM 并验证

引用 4.1/2.1 的 VM 模板,volumes 指向刚导入的 PVC:

yaml
volumes:
- name: rootdisk
  persistentVolumeClaim:
    claimName: migrated-vm-rootdisk
bash
kubectl apply -f migrated-vm.yaml
virtctl console migrated-vm        # 观察引导,确认无文件系统/网络报错

5.8 转换注意事项

检查项说明
驱动客户机需有 virtio 驱动;现代 Linux 自带,Windows 需预装 virtio-win
磁盘总线统一用 bus: virtio,性能最佳
固件源机若是 UEFI 启动,VM 需配 firmware.bootloader.efi
网络默认走 masquerade,客户机网卡建议改回 DHCP
容量PVC storage ≥ 源磁盘虚拟大小(不是实际占用)
cloud-init若源机装过,注意清理,避免与注入配置冲突
License/绑定检查软件是否绑定 MAC/CPU,必要时固定 macAddress

批量迁移时:先转一台做"金盘",验证通过后用第 7 章克隆快速复制。


6. 如何备份

6.1 备份对象与策略分层

对象备份方式频率建议
VM 定义(YAML)入库 Git(GitOps)每次变更
磁盘数据VM Snapshot / Export / Velero每日
平台配置(KubeVirt CR/CRD)kubectl get -o yaml 入库每次变更
etcdRKE2 自带快照 + 异地每日

原则(3-2-1):3 份数据、2 种介质、1 份异地。快照和原数据同机不算备份。

6.2 方案一:VirtualMachineSnapshot(磁盘支持快照时首选)

要求 StorageClass 支持 CSI VolumeSnapshot。NFS subdir provisioner 不支持, 此时跳到方案二。

bash
# 建议先停或静默客户机(装了 qemu-guest-agent 可文件系统冻结)
virtctl stop rocky9-vm2
yaml
apiVersion: snapshot.kubevirt.io/v1beta1
kind: VirtualMachineSnapshot
metadata:
  name: rocky9-snap-20260903
spec:
  source:
    apiGroup: kubevirt.io
    kind: VirtualMachine
    name: rocky9-vm2
bash
kubectl apply -f snap.yaml
kubectl get virtualmachinesnapshot rocky9-snap-20260903   # PHASE=Succeeded

恢复(先停目标):

yaml
apiVersion: snapshot.kubevirt.io/v1beta1
kind: VirtualMachineRestore
metadata:
  name: rocky9-restore
spec:
  target:
    apiGroup: kubevirt.io
    kind: VirtualMachine
    name: rocky9-vm2
  virtualMachineSnapshotName: rocky9-snap-20260903

6.3 方案二:VirtualMachineExport 导出(NFS 环境通用)

把磁盘导出为文件/镜像,天然适合异地备份与跨集群迁移

yaml
apiVersion: export.kubevirt.io/v1beta1
kind: VirtualMachineExport
metadata:
  name: rocky9-export
spec:
  source:
    apiGroup: kubevirt.io
    kind: VirtualMachine
    name: rocky9-vm2
bash
kubectl apply -f export.yaml
kubectl get virtualmachineexport rocky9-export    # 等待 Ready,拿到导出 URL/secret
# 用 virtctl 拉取
virtctl export vm rocky9-vm2 --output=rocky9-backup.tar.gz
# 再把文件放到 NAS/对象存储异地保存

6.4 方案三:Velero(集群级、含 PVC 数据)

用 Velero + node-agent(restic/kopia)备份整个命名空间的 VM 与 PVC:

bash
# 备份前先停 VM 保证一致性(或用 fs-freeze)
velero backup create kubevirt-vms-20260903 \
  --include-namespaces default \
  --include-resources virtualmachines.kubevirt.io,persistentvolumeclaims
velero schedule create kubevirt-daily --schedule="0 2 * * *" --ttl 168h

6.5 备份验证(必做)

备份不演练等于没备份:

bash
# 定期从备份恢复到临时命名空间/新 VM,启动验证数据完整
kubectl get vm -n restore-test
virtctl console restored-vm

7. 如何克隆

7.1 整台克隆:VirtualMachineClone(推荐)

一条 CR 克隆 VM + 所有磁盘 + 相关 Secret/ConfigMap:

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-vm3          # 目标(新名字)
bash
kubectl apply -f clone.yaml
kubectl get virtualmachineclone clone-rocky9    # PHASE=Succeeded
virtctl start rocky9-vm3

克隆出的 VM 拥有独立磁盘,与源互不影响。注意目标标签要改唯一, 避免 Service 误匹配。

7.2 只克隆磁盘:CDI DataVolume

yaml
apiVersion: cdi.kubevirt.io/v1beta1
kind: DataVolume
metadata:
  name: newvm-rootdisk
spec:
  source:
    pvc:
      namespace: default
      name: rocky9-vm2-disk       # 源 PVC
  pvc:
    storageClassName: vm-nas
    accessModes: [ReadWriteMany]
    resources:
      requests:
        storage: 20Gi

CDI 智能克隆优先走 CSI 快照(秒级),不支持快照时自动退化为网络复制。

7.3 黄金镜像批量发放(生产最佳实践)

源 qcow2 导入一次 → 金盘(golden-rocky9)→ DataSource 版本化
                → 每台新 VM 从 DataSource 克隆(秒级开盘)
yaml
# ① DataSource 指向金盘
apiVersion: cdi.kubevirt.io/v1beta1
kind: DataSource
metadata:
  name: rocky9-golden
spec:
  source:
    pvc: { namespace: default, name: golden-rocky9 }
---
# ② 新 VM 的 dataVolumeTemplates 里引用
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: web-vm-001
spec:
  dataVolumeTemplates:
  - metadata: { name: web-vm-001-root }
    spec:
      sourceRef:
        kind: DataSource
        name: rocky9-golden       # ★ 指向金盘
      pvc:
        storageClassName: vm-nas
        accessModes: [ReadWriteMany]
        resources: { requests: { storage: 20Gi } }

配合 DataImportCron 可定时从镜像库刷新金盘版本,实现"镜像升级一键下发"。


8. 如何灾备

8.1 灾备分层模型

第一层:组件高可用   → virt-* 多副本 + PDB,控制面自愈(现网已具备)
第二层:VM 故障自愈  → runStrategy: Always + 共享存储 + 容忍度,节点宕机分钟级恢复
第三层:维护零停机   → evictionStrategy: LiveMigrate,滚动维护不中断
第四层:数据级恢复   → 快照/导出/异地备份(第 6 章)
第五层:站点级灾备   → 跨集群/异地重建(本节重点)

8.2 站点级灾备:跨集群恢复

目标:主集群整体不可用时,在备用集群恢复业务。

前置:平时就要做好的三件事

事项说明
VM 定义入 Git所有 VM/Service/NAD YAML 版本化,可一键重放
磁盘定期异地备份用第 6 章方案把磁盘导出到独立存储/对象存储
备用集群就绪备用集群预装同版本 KubeVirt + CDI + 相同 StorageClass

灾难发生时的恢复流程

① 确认主集群不可恢复,宣布切换
② 备用集群 apply Git 中的 VM/网络定义
③ 从异地备份恢复磁盘:
   - 方案 A:DataVolume source http 重新导入镜像
   - 方案 B:从备份的 PVC 快照/导出文件恢复
④ 修正存储类/网段差异(StorageClassName、静态 IP)
⑤ 逐台启动验证,切流量(DNS/负载均衡指向备用集群)

恢复磁盘示例(从导出文件重新导入):

yaml
apiVersion: cdi.kubevirt.io/v1beta1
kind: DataVolume
metadata:
  name: dr-vm-rootdisk
spec:
  source:
    http:
      url: "http://<备份存储>/backups/rocky9-backup.disk.img"
  pvc:
    storageClassName: vm-nas-dr      # 备用集群的 SC
    accessModes: [ReadWriteMany]
    resources: { requests: { storage: 40Gi } }

8.3 数据保护增强(可选)

  • 存储级复制:商用 NAS 远程复制 / Ceph 跨集群镜像,RPO 可达分钟级;
  • 厂商 CSI 快照异地化:快照导出到第二台存储;
  • RPO/RTO 定义
    • RPO(数据丢失容忍):决定备份/复制频率;
    • RTO(恢复时间目标):决定是冷备重建还是热备双活。

8.4 灾备演练(必须定期做)

演练项频率验证点
单节点宕机自愈季度VM 自动在其他节点恢复
热迁移季度维护窗口零中断
快照/备份恢复季度数据完整、可启动
站点级切换半年/年备用集群端到端恢复

现网风险盘点与加固清单见 ../kubevirt-storage-ha-guide.md


9. 附录:命令速查与 FAQ

9.1 命令速查

bash
# --- 生命周期 ---
virtctl start/stop/restart/pause/unpause <vm>
virtctl migrate <vm>                     # 热迁移
virtctl vm expand <vm> --memory --cpu    # 在线扩规格
virtctl console/vnc/ssh <vm>             # 接入

# --- 磁盘 ---
kubectl get dv                            # DataVolume 状态
virtctl imageupload dv <name> -f x.qcow2 # 上传镜像
virtctl guestfs <pvc>                     # 临时 Pod 挂载改盘

# --- 快照/克隆/导出 ---
kubectl get virtualmachinesnapshot / virtualmachineclone / virtualmachineexport

# --- 网络 ---
kubectl get net-attach-def               # Multus 网络
virtctl expose vm <vm> --port 22 --type NodePort
kubectl get vmi <vm> -o jsonpath='{.status.interfaces}'   # VM IP

# --- 排障 ---
kubectl describe vmi <vm>
kubectl logs virt-launcher-<vm>-xxx -c compute
kubectl get events -n default --sort-by=.lastTimestamp

9.2 FAQ

Q1:Pod IP 能当固定业务 IP 吗? 不能。Pod IP 随重建变化,固定访问用 NodePort 或 Multus 静态 IP(见 3.2)。

Q2:为什么我的 VM 不能热迁移? 多数是磁盘非 ReadWriteMany(本地盘/RWO)。换共享存储或接受冷迁移。

Q3:改了 userData/networkData 为什么没生效? cloud-init 只在首次启动生效。需清理客户机 /var/lib/cloud/instances 或重建磁盘。

Q4:NFS 上能做快照备份吗? nfs-subdir-provisioner 不支持 CSI 快照,用 VirtualMachineExport 或 Velero(见第 6 章)。

Q5:导入后磁盘文件叫什么? Filesystem PVC 上固定为 disk.img(raw 格式),勿手工塞 qcow2。

Q6:怎么知道宿主机资源不够了? 看两类信号:① 节点真实水位——CPU/内存/磁盘利用率、节点 MemoryPressure/DiskPressure condition、kubelet 驱逐;② 调度容量—— requests/allocatable 比值 > 85%、virt-launcher Pod Unschedulable、 VMI 卡 Scheduling。完整 PrometheusRule 告警规则与定位命令见教材 kubevirt-tutorial-beginner-to-master.md 16.5~16.7。

Q6:如何批量建同配置 VM? 金盘 + DataSource + dataVolumeTemplates(见 7.3)。

Q7:VM 卡在 Pending/Scheduling?kubectl describe vmi:多为 /dev/kvm 缺失、资源不足、PVC 未 Bound。

9.3 相关文档索引

主题文档
系统理论kubevirt-tutorial-beginner-to-master.md
完整部署记录../rke2-kubevirt-deployment-guide.md
CDI 离线部署../cdi-offline-deployment-guide.md
NAS 存储细节../kubevirt-nas-storage-guide.md
存储高可用../kubevirt-storage-ha-guide.md
网络/SSH/密码xxx

文档维护:本文档基于 2026-09-03 现网环境编写。KubeVirt/CDI 升级后, 请以官方文档复核 API 字段;重大变更请同步更新本文档并记录日期。