1. 概述

前两篇已经完成了 Harvester 的定位、核心架构和安装部署。到了第三篇,重点从“平台能不能跑起来”转向“虚拟机能不能被稳定、可重复、可排障地交付”。对于习惯 VMware、Proxmox 或传统 KVM 的运维人员来说,Harvester 的虚拟机管理界面并不难上手,但真正需要理解的是:Harvester 不是把一个传统虚拟化平台简单换了 UI,而是把虚拟机声明成 Kubernetes 资源,再由 KubeVirt、Longhorn、Multus、调度器和 Harvester 控制器共同完成生命周期管理。

本文按一个典型运维场景展开:在已经安装好的 Harvester 集群上创建 Linux 虚拟机,完成镜像、磁盘、网络、cloud-init、访问、扩容、迁移、快照备份和排障闭环。读完之后,你应该能够回答三个问题:

  1. 一台 Harvester 虚拟机从创建到运行,背后经过哪些资源和控制器。
  2. 虚拟机的 CPU、内存、磁盘、网络、启动策略和调度规则如何影响后续运维。
  3. 当虚拟机无法启动、无法访问、无法迁移或快照失败时,应该按什么顺序收集证据。

本文中的功能说明以 Harvester 官方 v1.7/v1.8 文档核对,生产版本选择仍应以 SUSE Support Matrix 标记的 Stable 版本为准。验证环境建议至少包含 3 个 Harvester 节点、可用的 Longhorn 默认 StorageClass、一个可访问的 VLAN 或管理网络,以及一份已导入的 Linux cloud image。

2. 虚拟机不是孤立对象

在 Harvester UI 中,虚拟机看起来像一个单独的对象:有名称、CPU、内存、磁盘、网卡和电源状态。但从 Kubernetes 视角看,它至少牵涉以下几类资源:

层级 关键对象 作用
用户入口 Harvester VM、VM Image、SSH Key、CloudInit 给运维人员提供表单化管理入口
KubeVirt VirtualMachineVirtualMachineInstancevirt-launcher Pod 把虚拟机声明、运行实例和 QEMU/KVM 进程串起来
Kubernetes Namespace、Pod、Secret、PVC、Affinity、Node Selector 提供调度、配置、访问控制和资源隔离
Longhorn Volume、Replica、Snapshot、Backup 为虚拟机磁盘提供分布式块存储
网络插件 mgmt network、VLAN network、NetworkAttachmentDefinition 决定虚拟机从哪个网络收发流量
运维能力 Migration、Snapshot、Backup、Console、Guest Agent 支撑迁移、保护、访问和状态采集

下面的依赖图把一台虚拟机的主要对象放在一起。它不是为了记住所有 CRD 名称,而是提醒你:修改虚拟机配置时,不要只盯着 UI 表单,要同时考虑调度、存储、网络和来宾系统状态。

图中将虚拟机依赖关系整理成可复盘结构,下面的内容会沿着这些边界继续展开。 创建虚拟机时,Harvester 会把 UI 中的选择落到 KubeVirt 和 Kubernetes 资源上。虚拟机真正启动后,VirtualMachineInstance 会对应一个 virt-launcher Pod,Pod 内部承载 QEMU/KVM 进程,磁盘通过 PVC 连接到 Longhorn Volume,网络则由默认管理网络或额外 VLAN 网络提供。

3. 创建前的准备清单

不要急着点“Create VM”。在 Harvester 中,很多后续问题都来自创建阶段没有把镜像、网络、磁盘和启动策略想清楚。建议每次创建新业务虚拟机前先完成下面的准备。

3.1 明确命名和命名空间

Harvester 支持把虚拟机放在不同 namespace 中。官方文档中特别提醒,只有 harvester-public namespace 对所有用户可见。实际生产中建议不要把所有虚拟机都丢进 default

namespace 规划 适用方式
prod-* 生产业务,如 prod-erpprod-monitoring
test-* 测试、验证、升级演练
infra-* DNS、NTP、跳板机、监控采集器等基础服务
harvester-public 需要被多用户共享查看的通用资源

命名建议使用 业务-角色-序号,例如 erp-db-01mon-zbx-proxy-01k8s-rke2-master-01。这样排障时从 VM 名称就能判断所属系统和角色,也方便用标签、监控和备份策略做分组。

3.2 准备镜像

Harvester 创建虚拟机通常依赖 VM Image。Linux 场景优先选择 cloud image,例如 Ubuntu Cloud Image、Rocky Linux GenericCloud、openSUSE Cloud Image。这类镜像已经适配 cloud-init,适合通过 SSH Key、用户数据和网络数据完成首次启动配置。

镜像准备时重点检查四件事:

  1. 镜像格式是否为 Harvester 支持的格式,常见为 qcow2raw
  2. 镜像虚拟大小是否小于或等于创建虚拟机时配置的根磁盘大小。
  3. 镜像内是否安装并启用了 qemu-guest-agent
  4. 镜像内的 cloud-init datasource 是否能识别 NoCloud 配置。

官方文档明确提醒:使用 VM image 创建 volume 时,volume 大小必须大于或等于镜像大小,尤其是 qcow2 镜像,因为 qcow2 的虚拟大小通常大于物理文件大小。如果配置的 volume 小于底层镜像虚拟大小,可能导致卷损坏。

3.3 准备 SSH Key 和 cloud-init

对于 Linux 虚拟机,建议把密码登录视为例外,而不是默认。标准做法是:

  1. 在 Harvester 中提前维护 SSH Key。
  2. 使用 cloud-init 创建默认运维用户。
  3. 禁止 root 密码登录。
  4. 首次启动后通过配置管理工具继续收敛系统状态。

示例 cloud-init 可以从最小配置开始:

yaml
#cloud-config
hostname: demo-linux-01
manage_etc_hosts: true
users:
  - name: ops
    groups: sudo
    shell: /bin/bash
    sudo: "ALL=(ALL) NOPASSWD:ALL"
    ssh_authorized_keys:
      - ssh-ed25519 AAAA_REPLACE_WITH_REAL_KEY ops@example
ssh_pwauth: false
package_update: true
packages:
  - qemu-guest-agent
runcmd:
  - systemctl enable --now qemu-guest-agent || true

这个配置的目标很简单:让虚拟机首次启动后有可登录用户、有主机名、有 guest agent,并尽量避免弱密码入口。不同发行版的包名和服务名可能略有差异,生产模板应在同版本镜像上验证。

3.4 规划网络入口

Harvester 默认会给虚拟机添加 management network。官方文档说明,如果已经配置 VLAN 网络,可以移除默认 management network。更重要的是,官方也提醒了一个常见陷阱:当虚拟机同时连接 mgmt 网络和 VLAN 网络时,来宾系统中的默认路由可能被 VLAN 网关覆盖,导致节点无法通过虚拟机的 mgmt IP 访问它。

因此建议按用途选择网络模型:

网络模型 适用场景 注意事项
仅 mgmt 实验、基础测试、临时工具机 简单,但不适合承载正式业务流量
仅 VLAN 生产业务虚拟机 需要先建好 cluster network、network config 和 VM network
mgmt + VLAN 需要平台侧管理 IP 和业务 IP 分离 必须明确默认路由、DNS 和回包路径
多 VLAN 多网卡业务、网络设备、代理节点 注意节点覆盖范围和迁移目标可用性

3.5 确认资源与调度边界

Harvester 文档建议,分配给单台虚拟机的 vCPU 数量不要超过宿主机物理处理器线程数。这个建议很朴素,但很容易被忽略。资源规划时至少要确认:

  1. CPU 和内存是否有足够余量。
  2. 是否启用了资源 overcommit,是否符合业务 SLA。
  3. 根磁盘和数据盘的 StorageClass 是否正确。
  4. 是否设置了 strict affinity 或 node selector。
  5. 是否计划后续 live migration。

如果虚拟机未来需要在节点维护、升级或故障处置时迁移,不要把它强绑定到单个节点,也不要随意启用只有少数节点满足的 CPU pinning、网络或标签约束。

4. 从 UI 创建一台 Linux 虚拟机

Harvester 官方文档把创建入口分为 UI、API 和 Terraform。日常运维中 UI 最直观,适合首次建立模板和验证参数;批量交付则应转向 API、Terraform 或 GitOps。

4.1 基础信息

进入 Virtual Machines 页面,选择创建单台或多台 VM。基础信息建议这样填写:

字段 建议
Namespace 使用业务或环境命名空间
Name 使用 业务-角色-序号
Template Linux cloud image 可选择 raw-image 或对应模板
CPU 从 2 vCPU 起步,按业务压测调整
Memory 从 2 GiB 或 4 GiB 起步,不要把全部节点内存分完
SSHKey 选择已验证的公钥
Run Strategy 默认 RerunOnFailure,关键服务可按策略调整

Run Strategy 是 Harvester 虚拟机管理中很重要但容易被跳过的字段。官方文档说明,旧版本曾使用布尔型 running 字段,但它无法表达“用户在来宾系统内正常关机后不要自动拉起”这类需求,因此引入 RunStrategy。常见值可以这样理解:

RunStrategy 行为 适用场景
Always 实例应始终存在,异常退出会重新创建 强要求常驻的基础服务
RerunOnFailure 失败后重建,来宾系统正常关机后不重建 默认选择,适合大多数业务 VM
Manual 只通过显式 start/stop/restart 控制 测试机、模板机、临时机
Stop 不应存在运行实例 保留配置但停止运行

如果你来自 VMware,容易把 Run Strategy 理解成“开机状态”。更准确地说,它表达的是控制器应该如何维持虚拟机实例的期望状态。

4.2 磁盘配置

Volumes 页签中选择镜像并配置根磁盘。官方文档说明,第一个磁盘默认作为 root disk,启动顺序可以通过拖拽或箭头调整。磁盘类型常见有两类:

类型 说明 建议
disk 普通可读写磁盘 根盘和数据盘默认选择
cd-rom 只读光驱 ISO 安装、驱动盘、Windows virtio 驱动

如果使用外部存储,文档要求正确选择 StorageClass 和 Volume Mode。例如 nfs-csi StorageClass 需要 Filesystem volume mode。对于普通 Harvester + Longhorn 环境,默认 StorageClass 通常已经足够,但生产环境仍建议把不同业务级别拆成不同 StorageClass,例如:

StorageClass 用途
longhorn 默认通用块存储
longhorn-repl-2 测试环境或容量敏感场景
longhorn-repl-3 生产默认
longhorn-fast NVMe 节点池、数据库或高 I/O 场景

如果后续会做快照、备份或跨节点迁移,根盘和关键数据盘应使用具备多副本能力的持久卷,不要用只适合临时分发的 container disk 承载核心数据。官方文档对 container disk 的定位也很清楚:它适合批量复制大量 VM 工作负载或注入不要求持久化的驱动与只读输入,不适合要求 root disk 跨重启持久保存的工作负载。

4.3 网络配置

Networks 页签中,至少需要决定是否保留 management network,以及是否添加 VLAN network。Harvester 支持通过不同 interface type 暴露给来宾系统,常见是 masqueradebridge。在实际使用中,建议采用下面的决策方式:

4.3 网络配置

图中把网络配置拆成虚拟机接口、网络对象和节点数据面的关系,下面的内容会沿着这些边界继续展开。 这张决策图的重点是先决定业务流量从哪里走,再决定是否保留 mgmt。不要为了“多一条路更安全”随意加双网卡,双网卡最常见的问题就是默认路由、DNS、源地址选择和回包路径不一致。

如果业务 VLAN 使用 DHCP,虚拟机内的网卡应设置为 DHCP。如果使用静态地址,建议通过 cloud-init network data 写入,不要依赖人工登录后再改。示例:

yaml
version: 2
ethernets:
  enp1s0:
    dhcp4: false
    addresses:
      - 10.20.30.51/24
    gateway4: 10.20.30.1
    nameservers:
      addresses:
        - 10.20.30.10
        - 10.20.30.11

不同 Linux 发行版的网卡命名可能不同,模板化前应先在同一镜像上启动一台测试机确认接口名。对于 Ubuntu,需要特别注意 machine-id 与 DHCP client identifier 的关系。Harvester 备份恢复文档提醒,如果没有设置 dhcp-identifier: mac,恢复后的 Ubuntu VM 可能因为 netplan 默认使用 machine ID 作为 DHCP client identifier 而拿到与原 VM 相同的 IP,导致网络冲突。

4.4 高级选项

高级选项包括 OS Type、cloud-init、调度规则、资源预留、CPU 模型、CPU pinning、注解等。不要一次性打开所有高级能力,建议按业务需求逐项启用。

高级能力 何时启用 风险
cloud-init Linux 初始化、SSH Key、网络、软件包 YAML 错误会导致首次启动配置失败
Node Scheduling 合规、硬件依赖、网络覆盖限制 可能导致不可调度或不可迁移
VM Scheduling 同业务亲和、反亲和、高可用分布 strict 规则会影响升级 pre-drain
CPU Pinning NFV、数据库、低延迟负载 依赖节点 CPU Manager,影响迁移范围
Reserved Memory OOM、内存开销明显的 VM 设置过高降低集群资源利用率
Custom IP annotation guest agent 缺失时手工显示 IP 只是 UI 展示,不代表网络真实可达

官方文档说明,Harvester 会根据网络、CPU pinning 等定义自动给 VM 添加调度约束。例如连接某个 cluster network 的 VM 只会调度到覆盖该 network configuration 的节点;启用 CPU pinning 的 VM 只会调度到启用 CPU Manager 的节点。自动规则由 Harvester webhook 维护,手工改动可能被回滚。

5. 用 YAML 理解虚拟机定义

即使日常主要使用 UI,也建议至少能读懂 VirtualMachine YAML。下面是一个经过简化的 Linux 虚拟机定义,用于理解 Harvester 与 KubeVirt 的边界。

yaml
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: demo-linux-01
  namespace: prod-demo
  labels:
    app: demo
    role: web
spec:
  runStrategy: RerunOnFailure
  template:
    metadata:
      labels:
        kubevirt.io/domain: demo-linux-01
    spec:
      domain:
        cpu:
          cores: 2
          sockets: 1
          threads: 1
        memory:
          guest: 4Gi
        devices:
          disks:
            - name: rootdisk
              disk:
                bus: virtio
            - name: cloudinitdisk
              disk:
                bus: virtio
          interfaces:
            - name: default
              masquerade: {}
              model: virtio
        machine:
          type: q35
      networks:
        - name: default
          pod: {}
      volumes:
        - name: rootdisk
          persistentVolumeClaim:
            claimName: demo-linux-01-rootdisk
        - name: cloudinitdisk
          cloudInitNoCloud:
            userDataSecretRef:
              name: demo-linux-01-cloudinit

这段 YAML 里有几个排障时很有用的观察点:

  1. spec.runStrategy 决定控制器如何维持运行状态。
  2. domain.cpudomain.memory 决定来宾系统可见资源。
  3. devices.disksvolumes 通过名称关联。
  4. interfacesnetworks 通过名称关联。
  5. cloud-init 可以通过 Secret 注入,避免把敏感内容直接写进公开 YAML。

你可以用下面的命令观察 Harvester UI 创建后的实际资源。命令中的 namespace 和 VM 名称需要替换成自己的值:

bash
NS=prod-demo
VM=demo-linux-01

kubectl get vm -n "$NS" "$VM" -o wide
kubectl get vmi -n "$NS" "$VM" -o wide
kubectl get pod -n "$NS" -l vm.kubevirt.io/name="$VM" -o wide
kubectl get pvc -n "$NS" | grep "$VM"
kubectl describe vm -n "$NS" "$VM"

当 UI 展示的信息不够时,describe vmdescribe vmi 往往能看到调度失败、磁盘挂载失败、网络附加失败、迁移失败等事件。

6. 首次启动后的验证

创建完成不等于交付完成。建议每台新虚拟机至少经过“平台侧、网络侧、来宾侧、保护侧”四类验证。

6. 首次启动后的验证

图中把首次启动后的验证点整理为启动、网络、存储和来宾系统几条证据线。 这张时序图适合用来定位问题在哪一段:如果 PVC 没有创建或绑定,问题在存储;如果 VMI 没有调度,问题在调度或资源;如果 VM 已运行但没有 IP,问题在 guest agent、DHCP、cloud-init 或网络路由。

6.1 平台侧验证

bash
NS=prod-demo
VM=demo-linux-01

kubectl get vm -n "$NS" "$VM"
kubectl get vmi -n "$NS" "$VM"
kubectl get pod -n "$NS" -l vm.kubevirt.io/name="$VM"
kubectl get events -n "$NS" --sort-by=.lastTimestamp | tail -n 30

正常情况下,你应该看到 VM 处于 Running 或期望的状态,VMI 已创建,virt-launcher Pod 处于 Running。事件中不应反复出现 FailedSchedulingFailedMountFailedCreatePodSandBoxErrImagePull 等错误。

6.2 存储侧验证

bash
kubectl get pvc -n "$NS" | grep "$VM"
kubectl -n longhorn-system get volumes.longhorn.io | grep "$VM"

如果 PVC 一直 Pending,优先检查 StorageClass、节点可用磁盘、Longhorn 节点状态和副本调度。如果 Longhorn Volume degraded,需要先恢复副本健康,再考虑业务层操作。

6.3 网络侧验证

在 Harvester UI 中确认 VM IP 后,从管理网络或业务网络测试:

bash
ping -c 4 10.20.30.51
ssh ops@10.20.30.51

如果 UI 没有显示 IP,不一定代表虚拟机没有 IP。官方文档说明,可以通过 harvesterhci.io/custom-ip annotation 在 UI 中手工显示 IP,这对缺少 qemu-guest-agent 的虚拟机有帮助。但这只是展示能力,不是连通性验证。真正的验证仍应进入虚拟机控制台或从网络侧测试。

6.4 来宾系统验证

登录虚拟机后建议执行:

bash
hostnamectl
ip addr
ip route
cloud-init status --long || true
systemctl status qemu-guest-agent --no-pager || true
df -h
lsblk

重点看主机名、路由、DNS、磁盘大小、guest agent 状态和 cloud-init 是否成功完成。cloud-init 失败并不总是阻止虚拟机启动,但会影响用户、SSH Key、网络和软件包安装,后续排障成本很高。

7. 生命周期操作

Harvester 的虚拟机生命周期操作包括启动、停止、重启、编辑、克隆、快照、备份、迁移和删除。不同操作对底层资源的影响不同,不能只按按钮名称理解。

7.1 启动、停止和重启

如果 Run Strategy 是 Manual,启动和停止基本由操作员控制。如果是 AlwaysRerunOnFailure,控制器会根据策略维持期望状态。建议:

  1. 计划停机前,在来宾系统内正常关机,确保文件系统和数据库优雅退出。
  2. 如果只是平台侧维护,不要随意把 Run Strategy 改成 Stop 后忘记恢复。
  3. 如果 VM 反复自动拉起,先检查 Run Strategy,再检查来宾系统关机原因。

7.2 编辑 CPU 和内存

CPU 和内存调整看似简单,但需要区分“配置已修改”和“来宾系统已生效”。某些能力支持热插拔,某些修改需要重启虚拟机。操作建议:

  1. 先确认业务是否支持资源在线变化。
  2. 记录修改前的 CPU、内存、节点和业务负载。
  3. 低峰期修改配置。
  4. 在来宾系统内确认 lscpufree -h、业务进程和监控指标。

不要用资源扩容掩盖应用内存泄漏、数据库慢查询或磁盘 I/O 饱和。虚拟机层面的 CPU Ready、节点压力、Longhorn 延迟和来宾系统负载应该结合判断。

7.3 热插拔磁盘

Harvester 官方文档在 v1.7 中列出 Hot-Plug Volumes。热插拔数据盘适合业务扩容、迁移数据或临时挂载工具盘。操作前要确认:

  1. 来宾系统内核和发行版能识别热插拔块设备。
  2. 文件系统扩容步骤已验证。
  3. 备份或快照已完成。
  4. 新卷 StorageClass、副本数和容量符合业务需求。

Linux 内常见验证命令:

bash
lsblk
dmesg | tail -n 50
sudo file -s /dev/vdb
sudo mkfs.xfs /dev/vdb
sudo mkdir -p /data
sudo mount /dev/vdb /data
df -h /data

生产环境不建议直接用裸设备名写 /etc/fstab,因为设备名可能变化。应优先使用 UUID:

bash
sudo blkid /dev/vdb
echo 'UUID=<uuid> /data xfs defaults,nofail 0 2' | sudo tee -a /etc/fstab
sudo mount -a

7.4 克隆虚拟机

克隆适合快速复制测试环境、创建同版本节点或生成一次性验证机。克隆前必须处理身份唯一性:

项目 为什么要处理
hostname 避免监控、日志和配置管理混淆
machine-id 避免 DHCP、systemd、日志身份冲突
SSH host key 避免 SSH 安全警告和身份复用
应用实例 ID 避免业务集群误认为同一节点
IP 地址 避免网络冲突

Linux 模板机在关闭前可执行类似清理动作,具体命令需按发行版验证:

bash
sudo cloud-init clean --logs
sudo truncate -s 0 /etc/machine-id
sudo rm -f /var/lib/dbus/machine-id
sudo rm -f /etc/ssh/ssh_host_*
sudo shutdown -h now

不要在没有清理身份的情况下把生产数据库、域控、许可证服务器或集群控制节点直接克隆出来并接入同一网络。

8. Live Migration 与节点维护

Harvester 的 live migration 依赖 KubeVirt。手工迁移可以在 VM 菜单中选择 Migrate,自动批量迁移则常见于 Harvester 升级和节点维护场景。官方文档说明,迁移触发后会创建 VirtualMachineInstanceMigration 对象,并通过 VMI 的迁移状态关联。手工触发的迁移对象名称通常以前缀 VM 名称开头,自动批量迁移对象通常带有 kubevirt-evacuation- 前缀。

8. Live Migration 与节点维护

图中把 Live Migration 与节点维护的前置条件和验证路径串联起来,后续步骤按这些边界展开。 迁移失败常见原因包括:

  1. 集群只有一个节点。
  2. VM 被判定为 non-migratable。
  3. 已有迁移正在运行或等待。
  4. 节点调度规则、网络覆盖、CPU pinning 或 CPU model 限制导致目标节点不满足条件。
  5. 写入速率过高,内存页或磁盘块复制无法在合理时间内完成。

官方文档对 CPU model matching 有明确说明:如果 VM 没有指定 CPU model,默认使用 host-model,迁移时会要求目标节点支持相同迁移 CPU model 标签。若集群节点 CPU 型号差异较大,就可能出现某些 VM 只能在部分节点之间迁移的情况。

迁移前建议执行:

bash
NS=prod-demo
VM=demo-linux-01

kubectl get vm -n "$NS" "$VM" -o yaml | grep -A30 -E 'nodeSelector|affinity|cpu:|networks:'
kubectl get nodes --show-labels | grep -E 'cpu-model|network.harvesterhci.io|cpumanager'
kubectl get vmi -n "$NS" "$VM" -o wide

如果迁移失败,检查迁移对象:

bash
kubectl get vmim -A
kubectl describe vmim -n "$NS" <migration-name>
kubectl get vmi -n "$NS" "$VM" -o jsonpath='{.status.migrationState}'

对生产 VM 的建议是:在设计阶段就把可迁移性当作要求,而不是等节点维护时再修。尤其要谨慎使用单节点网络覆盖、严格反亲和、CPU pinning、特定主机标签和本地化存储。

9. 快照、备份与恢复

虚拟机管理不能只关注创建和运行。Harvester 通过 Longhorn 提供 VM snapshot、VM backup 和 restore 能力。快照更适合短期回滚点,备份更适合跨故障域保护。两者都不是数据库一致性和业务连续性的全部答案。

9.1 快照与备份的边界

能力 主要用途 适合保留多久 注意事项
VM Snapshot 升级前、配置变更前、短期回滚 短期 占用集群本地存储,不应长期堆积
VM Backup 故障恢复、跨集群恢复、长期保护 按备份策略 需要稳定的 NFS 或 S3 目标
应用备份 数据库、业务数据一致性 按业务 RPO/RTO 应用层仍需自有备份机制

官方文档说明,当 guest VM 连接了 QEMU Guest Agent 时,Harvester controller 会通过 KubeVirt 的 virt-freezer 对文件系统执行 freeze 操作,以提高备份和快照的一致性。这对高 I/O 或关键数据 VM 很重要,但它依赖来宾系统配置:部分 Linux 发行版可能受 SELinux 权限影响,Windows 则依赖 VSS 服务。

9.2 创建快照前检查

bash
NS=prod-demo
VM=demo-linux-01

kubectl get vmi -n "$NS" "$VM" -o wide
kubectl get pod -n "$NS" -l vm.kubevirt.io/name="$VM"
kubectl -n longhorn-system get volumes.longhorn.io | grep "$VM"

来宾系统内检查:

bash
systemctl status qemu-guest-agent --no-pager || true
cloud-init status --long || true
df -h

对于数据库 VM,建议在应用层也做一致性处理,例如数据库自身备份、停止写入、进入维护窗口或通过数据库原生工具创建恢复点。不要把虚拟机快照当成数据库备份的唯一手段。

9.3 恢复新虚拟机的网络风险

官方备份恢复文档特别提到 Ubuntu 的 DHCP 风险:恢复后的虚拟机会保留原 VM 的 machine ID,如果没有设置 dhcp-identifier: mac,netplan 默认可能使用 machine ID 作为 DHCP client identifier,从而拿到与原 VM 相同的 IP。这个问题在“从备份恢复一台新 VM 做验证”时尤其危险,因为原 VM 可能还在线。

建议在 Ubuntu cloud-init network data 中加入:

yaml
version: 2
ethernets:
  enp1s0:
    dhcp4: true
    dhcp-identifier: mac

如果是静态地址,恢复新 VM 时必须先断开业务网络,修改 IP、hostname、machine-id 和应用身份后再接入正式网络。

9.4 Longhorn V2 卷注意事项

Harvester v1.7 文档中提到,从 v1.7.0 开始,Harvester 支持 Longhorn V2 volumes 的备份和快照;但同一文档也警告,删除最新备份或最新快照、或者启用 Longhorn 的 Auto Cleanup Snapshot When Delete Backup 设置,可能阻塞相关 volume 后续操作,包括 volume snapshot、backup 和 live migration。官方说明当前没有可行 workaround,恢复 Longhorn Manager 功能可能需要删除受影响 volume。

这类限制对生产运维的含义很直接:

  1. 不要在不了解影响的情况下清理“最新”的备份或快照。
  2. 不要把备份清理策略和 Longhorn 设置交给多人随意修改。
  3. 对使用 Longhorn V2 volumes 的 VM,先在测试环境演练快照、备份、删除和恢复。
  4. 重要业务 VM 的保护策略应写成 runbook,而不是只靠 UI 操作习惯。

10. 常见故障排查

虚拟机故障排查要先定位层级,再处理具体原因。下面这张决策树适合放在值班手册中。

10. 常见故障排查

图中把常见故障按调度、镜像、网络、存储和来宾系统分层,排查时先定位层级再处理。

10.1 虚拟机创建后一直 Pending

排查顺序:

bash
NS=prod-demo
VM=demo-linux-01

kubectl describe vm -n "$NS" "$VM"
kubectl describe vmi -n "$NS" "$VM" || true
kubectl get pod -n "$NS" -l vm.kubevirt.io/name="$VM"
kubectl get events -n "$NS" --sort-by=.lastTimestamp | tail -n 50
kubectl describe nodes | grep -A8 "Allocated resources"

常见原因:

现象 可能原因 处理
FailedScheduling CPU/内存不足 降低 VM 规格或扩容节点
node selector 不满足 绑定了不存在的标签 修正调度规则
网络相关事件 VLAN network 未覆盖目标节点 检查 cluster network 和 network config
PVC Pending StorageClass 或 Longhorn 不健康 检查 Longhorn 节点和磁盘

10.2 虚拟机 Running 但没有 IP

先判断“没有 IP”是 UI 没显示,还是来宾系统真的没有拿到地址。

bash
kubectl get vmi -n "$NS" "$VM" -o yaml | grep -A20 interfaces
kubectl get pod -n "$NS" -l vm.kubevirt.io/name="$VM" -o wide

进入控制台后检查:

bash
ip addr
ip route
resolvectl status || cat /etc/resolv.conf
cloud-init status --long || true
journalctl -u systemd-networkd -u NetworkManager --no-pager -n 100
systemctl status qemu-guest-agent --no-pager || true

常见原因包括:cloud-init network data 接口名错误、DHCP 不可达、VLAN ID 配错、默认路由被第二张网卡覆盖、guest agent 未安装或未启动。解决时不要只在来宾系统手工改一次,而要回到模板、cloud-init 和 Harvester 网络定义中修正。

10.3 虚拟机无法迁移

检查:

bash
kubectl get vmim -A
kubectl describe vmi -n "$NS" "$VM"
kubectl get nodes --show-labels | grep -E 'cpu-model|network.harvesterhci.io|cpumanager'
kubectl get vm -n "$NS" "$VM" -o yaml | grep -A60 -E 'affinity|nodeSelector|networks|cpu'

处理原则:

  1. 如果只有一个节点满足网络覆盖或 CPU 条件,迁移失败是预期结果。
  2. 如果 strict anti-affinity 导致无目标节点,先评估是否可改成 preferred。
  3. 如果 CPU model 不匹配,统一节点硬件或按官方文档规划 cluster-level / individual VM CPU model。
  4. 如果迁移超时,观察业务写入速率、磁盘 I/O 和迁移完成超时设置。

10.4 快照或备份失败

检查:

bash
kubectl get volumesnapshot -A | grep "$VM" || true
kubectl -n longhorn-system get volumes.longhorn.io | grep "$VM"
kubectl -n harvester-system logs -l app=harvester --tail=200

来宾系统内检查 guest agent 与文件系统:

bash
systemctl status qemu-guest-agent --no-pager || true
df -h
mount
journalctl -u qemu-guest-agent --no-pager -n 100 || true

如果错误指向 filesystem freeze,按官方文档思路确认来宾系统是否支持 freeze/thaw,SELinux 或 Windows VSS 是否阻止操作。必要时在业务维护窗口内执行应用一致性备份,而不是强行依赖在线快照。

11. 批量交付与自动化建议

当 VM 创建流程稳定后,不建议长期依赖人工 UI 表单。Harvester 官方文档提供 API 和 Terraform 示例,生产交付可以按成熟度逐步演进。

在进入自动化之前,还要把 VM 扩容和迁移验收固化下来。虚拟机 CPU、内存、磁盘和网卡变更看起来只是几个字段,但它们分别影响调度、来宾系统、存储副本和网络策略。没有验收清单的自动化会把错误快速复制到更多 VM 上。

CPU 和内存扩容后,应确认 VM 是否需要关机、来宾系统是否识别新资源、监控阈值是否更新、应用授权是否按 CPU 或内存计费。磁盘扩容后,应确认 PVC 容量、Longhorn Volume 容量、来宾块设备、分区和文件系统都完成扩展。网卡变更后,应确认 NetworkAttachmentDefinition、VLAN、DHCP、默认路由和防火墙策略都符合预期。

Live Migration 的验收也不能只看任务成功。迁移前要确认目标节点有对应网络覆盖、存储副本健康、CPU model 兼容、目标节点资源足够;迁移中观察 VMI migration 对象和事件;迁移后验证业务端口、默认路由、磁盘 I/O、监控指标和备份任务。若迁移成功但业务丢包严重,说明前置条件或观察指标不完整。

这些验收项应作为 Terraform 模块、GitOps 流程或工单模板的输出,而不是写在个人笔记里。自动化越成熟,越要把“何时允许修改、修改后如何验证、失败后如何回滚”写成显式规则。

11.1 从 UI 到模板

第一阶段适合建立标准模板:

  1. 导入官方 cloud image。
  2. 创建一台最小 VM。
  3. 验证 cloud-init、SSH、guest agent、网络和快照。
  4. 清理 machine-id、SSH host key 和 cloud-init 状态。
  5. 关闭 VM,作为模板来源。

模板不是“装好软件的黄金镜像”这么简单。更好的模板应尽量保持基础、可升级、可审计,把业务差异留给 cloud-init、配置管理和部署流水线。

11.2 用 Terraform 描述虚拟机

当同类 VM 数量增加时,可以用 Terraform 管理。官方文档示例中,harvester_virtualmachine resource 可以描述 CPU、内存、run strategy、SSH key、网络接口、磁盘和 cloud-init Secret。团队使用 Terraform 时建议:

内容 建议
VM 规格 变量化,但限制可选档位
cloud-init 模板化,敏感内容放 Secret 管理
网络 不允许随意填 VLAN,使用模块封装
磁盘 区分根盘、数据盘、临时盘
标签 强制写入业务、环境、负责人
输出 输出 VM 名称、namespace、IP、SSH 入口

不要让每个项目组都复制一份 Terraform 资源块自行修改。更稳妥的方式是把“公司标准 VM”封装为模块,只开放必要参数。

11.3 用 GitOps 管理声明式资源

如果团队已经使用 Rancher、Fleet 或 Argo CD,可以把虚拟机相关资源纳入 GitOps。但要注意虚拟机不是无状态容器,GitOps 对 VM 的控制边界要谨慎:

  1. 适合声明 namespace、网络、镜像引用、标准 VM 模板和非敏感配置。
  2. 适合审计 Run Strategy、调度规则、标签和注解。
  3. 不适合频繁把运行中 VM 的临时状态强行收敛。
  4. 不适合把一次性迁移、恢复、故障处置操作直接写成长期期望状态。

虚拟机自动化的关键不是“所有东西都 YAML 化”,而是把可重复交付、可审计变更和可恢复状态区分清楚。

12. 生产管理基线

下面是一份可以直接放进 Harvester 运维规范的 VM 管理基线。

12.1 创建基线

  • 每台 VM 必须有明确 namespace、业务标签、负责人和用途。
  • Linux VM 默认使用 cloud-init 注入 SSH Key,不开放弱密码登录。
  • 根盘大小必须不小于镜像虚拟大小,并预留业务增长空间。
  • 生产 VM 默认使用多副本持久卷,不使用 container disk 承载持久数据。
  • VM 网络必须明确默认路由,不允许无说明的 mgmt + VLAN 双网卡配置。
  • 需要迁移能力的 VM 不绑定单节点,不使用只有单节点满足的网络或 CPU 规则。

创建基线还应覆盖镜像来源。镜像必须有来源、版本、校验方式、维护人和废弃日期。公共镜像只提供最小系统和标准 agent,不应把业务配置、临时账号、测试证书或个人 SSH Key 固化进去。模板越“万能”,越容易把历史包袱复制到所有新 VM。

命名也要在创建阶段解决。namespace 表达团队或业务域,VM 名称表达环境、业务和序号,标签表达负责人、重要性、备份等级和成本归属。不要把这些信息写在描述字段里。Harvester 背后是 Kubernetes,对象标签和命名会直接影响查询、审计、GitOps 和自动化筛选。

12.2 变更基线

  • CPU、内存、磁盘、网卡、调度规则和 Run Strategy 变更都应记录。
  • 变更前确认快照或备份策略,但数据库类业务还要做应用层保护。
  • VM 规格扩容后必须在来宾系统和监控系统中验证。
  • 删除 VM 前确认备份、快照、DNS、监控、CMDB 和配置管理记录。

变更基线要区分“平台配置变更”和“来宾系统变更”。给 VM 增加一块数据盘只是平台层动作,来宾系统还要识别磁盘、分区、格式化、挂载、写入 /etc/fstab 或更新应用路径。平台层显示 Volume 已 attached,不代表业务已经可用。变更单中应同时包含平台验收和来宾验收。

网卡和网络变更尤其需要回程路径检查。双网卡 VM 很容易出现默认路由漂移、源地址选择错误或安全组策略遗漏。变更后只 ping 网关不够,还要验证业务端口、DNS、NTP、监控探针和备份流量是否走预期网络。对数据库、中间件和域控类 VM,还要确认客户端访问路径没有被非预期网卡接管。

12.3 保护基线

  • 所有生产 VM 必须纳入备份策略。
  • 快照只作为短期回滚点,不作为长期备份。
  • 备份目标必须定期做恢复演练。
  • Ubuntu 或依赖 DHCP 的 VM 必须处理 machine-id 与 DHCP identifier 风险。
  • guest agent 应作为标准组件安装并启用。

保护基线不能只看是否存在备份任务。还要记录恢复等级:哪些 VM 只需要整机恢复,哪些需要文件级恢复,哪些需要应用一致性,哪些可以从模板重建。不同等级决定是否需要 guest agent、停写脚本、应用备份、外部数据库备份和定期恢复演练。

快照治理也要有上限。平台快照适合短期回滚,如果长期堆积,会增加容量压力和恢复复杂度。应用上线、系统补丁、配置调整前创建快照是合理的,但变更完成后应在规定时间内删除或转成备份。快照保留策略应由业务重要性和恢复窗口决定,而不是由操作人员习惯决定。

12.4 排障基线

12.4 排障基线

图中把生产排障固化为平台对象、网络与存储、来宾与业务三层证据链,强调先取证、再修复、最后归档。

  • 平台侧先看 VM、VMI、Pod、PVC、Event。
  • 存储侧看 Longhorn Volume、Replica、节点磁盘和 StorageClass。
  • 网络侧看 VM network、节点覆盖、来宾路由和 DHCP。
  • 来宾侧看 cloud-init、guest agent、系统日志和业务日志。
  • 迁移侧看 VirtualMachineInstanceMigration、CPU model、网络覆盖和调度规则。

12.5 运行态巡检

VM 运行后要有固定巡检。每日检查 VMI 状态、重启次数、Volume health、备份任务和关键告警;每周检查未使用快照、长期停止但未退役 VM、没有负责人标签的 VM、无备份策略的生产 VM;每月抽样做恢复演练和迁移演练。巡检不是为了生成报告,而是为了及时发现“能运行但不可恢复”的风险。

运行态巡检还要和容量治理联动。CPU 和内存长期过高可能需要扩容或应用优化,长期过低可能说明资源浪费;磁盘增长快要提前评估 Volume 扩容和备份窗口;网络错误和丢包要回到 VM Network、节点接口和交换机侧排查。Harvester 提供平台对象,监控系统提供指标,两者结合才能判断 VM 是否处于健康状态。

退役巡检同样重要。停止状态超过一定天数、没有监控目标、没有业务访问、备份长期失败的 VM,应进入确认流程。确认退役后,要释放 DNS、IP、监控、备份、CMDB 和配置管理记录,再删除 VM 和卷。直接删除 VM 容易留下孤立资源,长期保留无主 VM 则会消耗存储和安全治理精力。

13. 总结

Harvester 的虚拟机管理表面上是创建、开机、关机和改配置,实际核心是把虚拟机作为 Kubernetes 资源进行声明式管理。这个模型带来的好处是自动化、调度、存储、网络和 API 能力更统一;代价是排障时必须同时理解 KubeVirt、Longhorn、Kubernetes 调度和来宾系统。

本文从创建一台 Linux VM 开始,串起了镜像、磁盘、网络、cloud-init、Run Strategy、YAML 定义、首次验证、生命周期操作、live migration、快照备份、故障排查和自动化交付。实际落地时,建议先建立一套可验证的标准 VM 模板,再逐步把常见规格、网络、cloud-init 和保护策略固化为模块或 GitOps 资源。

下一篇将进入 Harvester 的《存储管理》,重点分析 Longhorn 存储池、磁盘、副本、StorageClass、性能、容量和故障恢复。

参考资料