Skip to content

03 · 运维手册:虚拟机生命周期(创建 / 镜像 / 启停 / 快照 / 清理)

环境:Harvester v1.8.2(Helm on RKE2)、KubeVirt 1.7.4-150700.3.24.2、CDI、Longhorn 1.11.2。 所有命令均可直接复制执行;带 ✓ 的结论为本环境实测。 配套清单:scripts/manifests/;端到端脚本:scripts/vm-e2e-test.sh


1. 命名空间与资源模型速览

对象说明
期望状态VirtualMachinekubevirt.io/v1VM 定义(含 dataVolumeTemplates
运行实例VirtualMachineInstance(VMI)每次启动生成一个;停机即回收
承载进程virt-launcher-<vm>-xxxxx Pod内含 qemu-kvm;一个 VMI 一个 Pod
磁盘DataVolumecdi.kubevirt.io/v1beta1)→ PVC → PV → volumes.longhorn.io四层状态需分别确认
镜像导入importer-<dv>-xxxx / importer-prime-<uid> PodCDI 导入器;RWX 走 populator 预克隆流程
快照VirtualMachineSnapshot / …SnapshotContentsnapshot.kubevirt.io/v1beta1KubeVirt 原生 API,Harvester v1.8 无自有快照 CRD
恢复VirtualMachineRestore(同上 API)目标 VM 必须停机
迁移VirtualMachineInstanceMigrationkubevirt.io/v104-运维手册-迁移与高可用.md

常用短名/全名(注意歧义):

bash
kubectl get vm,vmi,dv,pvc -n default
kubectl get volumesnapshots.snapshot.storage.k8s.io -A
kubectl get volumesnapshotclasses.snapshot.storage.k8s.io      # 不要用短名 vsc(会解析成 contents)
kubectl get virtualmachinesnapshots.snapshot.kubevirt.io -A
kubectl get volumes.longhorn.io -n longhorn-system

2. 磁盘规格选型矩阵(★ 最重要,实测结论)

accessModesvolumeMode可用性热迁移说明
ReadWriteOnceFilesystem推荐基线导入/引导/长期运行/快照/恢复流程全部验证通过(VM 连续运行 5h+ 无异常)
ReadWriteOnceBlockLonghorn 支持;qemu 直接操作块设备
ReadWriteManyBlockCDI importer:blockdev: cannot open /dev/cdi-block-volume: Permission denied(Longhorn RWX 走 NFS,不提供块设备)
ReadWriteManyFilesystem✗(本环境)✓(理论上)热迁移所需组合,但依赖 Longhorn RWX 数据面;本环境 shareEndpoint/shareState 为空、无 share-manager Pod → qemu-img 写盘失败

结论与规范

  1. 生产 VM 磁盘统一使用 ReadWriteOnce + Filesystem(或 Block),确保稳定可用;
  2. KubeVirt 热迁移硬性要求所有 PVC 为 RWX(实测报错 DisksNotLiveMigratable), Longhorn SC 的 migratable: "true" 不足以绕过;
  3. 因此在 Longhorn RWX 修好之前,跨节点移动 VM 一律用冷迁移(见 04 手册 §3,已实测通过);
  4. Harvester 源码对 RWX 的态度可作参考:
    go
    // pkg/util/virtualmachine/virtualmachine.go:169
    func volumeSupportRWXForVM(accessModes []corev1.PersistentVolumeAccessMode, provisioner string) bool {
        if provisioner == util.CSIProvisionerLonghorn {
            // Longhorn provisioner does not support RWX volume for VM
            return false
        }
        return slices.Contains(accessModes, corev1.ReadWriteMany)
    }

3. 创建虚拟机

3.1 方式一:Dashboard(推荐给业务方)

https://harvester.local:32735/ → Virtual Machines → Create:

  • 指定 CPU/内存、镜像(来自 Images)、磁盘大小、网络(默认 Management Network = masquerade)、cloud-init;
  • UI 会自动补齐 Harvester 需要的标签/注解(如 harvesterhci.io/creator)与网络配置, 比手写 YAML 更少踩坑(例如缺失 masquerade 接口会被 webhook 拒绝)。

3.2 方式二:kubectl + DataVolume(本次验证使用)

完整可用清单:scripts/manifests/vm-cirros.yaml(含 cloud-init Secret)。骨架:

yaml
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: vm-demo
  namespace: default
  labels:
    harvesterhci.io/creator: harvester     # Harvester 生态识别用
spec:
  runStrategy: Always                      # 与 spec.running 互斥,二选一
  template:
    metadata:
      labels: {harvesterhci.io/creator: harvester}
    spec:
      terminationGracePeriodSeconds: 30
      domain:
        machine: {type: q35}
        cpu: {cores: 1, sockets: 1, threads: 1}
        memory: {guest: 1Gi}
        resources:
          requests: {cpu: "1", memory: 1Gi}
          limits:   {cpu: "1", memory: 1Gi}
        devices:
          interfaces:
            - name: default
              masquerade: {}               # ★ 必需,否则 Harvester webhook 拒绝网络配置
          disks:
            - {name: disk-0,        disk: {bus: virtio}}
            - {name: cloudinitdisk, disk: {bus: virtio}}
      networks:
        - {name: default, pod: {}}         # 使用 Pod 网络(本环境 Calico VXLAN)
      volumes:
        - name: disk-0
          dataVolume: {name: vm-demo-disk-0}
        - name: cloudinitdisk
          cloudInitNoCloud: {secretRef: {name: cirros-cloudinit}}
  dataVolumeTemplates:
    - metadata: {name: vm-demo-disk-0, namespace: default}
      spec:
        pvc:
          accessModes: [ReadWriteOnce]     # ★ 见 §2 选型矩阵
          volumeMode: Filesystem
          resources: {requests: {storage: 2Gi}}
          storageClassName: harvester-longhorn
        source:
          http: {url: https://<内网镜像源>/cirros-0.6.2-x86_64-disk.img}

创建与观察:

bash
kubectl apply -f vm-demo.yaml
kubectl get dv,pvc,vm,vmi -n default -w        # 观察导入 → 调度 → 运行

实测状态流转(HTTP 源,镜像约 60MB):

dv : ImportScheduled → ImportInProgress(2.5%→99.6%) → Succeeded
pvc: Pending → Bound
vm : Provisioning → Starting → Running
vmi: Scheduling → Scheduled → Running        node=sza122102.local  ip=10.42.6.31

3.3 方式三:空盘(快速验证调度/存储/迁移链路)

yaml
        source:
          blank: {}          # 不下载任何镜像,秒级完成

实测:DV Succeeded 100%(75s 含调度),VM/VMI Running ✓ 用途:验证平台链路、压测调度、演练迁移;不能当业务 VM(无 OS,引导停在 SeaBIOS)。

3.4 创建后必查清单

bash
kubectl get vm,vmi -n default -o wide                      # 状态与落点节点
kubectl get pvc -n default <disk> -o jsonpath='{.spec.accessModes} {.spec.volumeMode} {.status.phase}'
kubectl get volumes.longhorn.io -n longhorn-system <pv> -o jsonpath='{.status.state} {.status.robustness} {.status.currentNodeID}'
kubectl get pod -n default -l kubevirt.io/domain=<vm> -o wide   # virt-launcher

网络连通性(从另一个节点验证跨节点 Calico VXLAN + masquerade):

bash
ping -c2 <vm-ip>
nc -vz -w3 <vm-ip> 22          # 实测 ICMP 与 SSH 22 均通 ✓

4. 启动 / 停止 / 重启

4.1 唯一正确姿势:runStrategy

bash
kubectl patch vm -n default <vm> --type=merge -p '{"spec":{"runStrategy":"Halted"}}'   # 停止
kubectl patch vm -n default <vm> --type=merge -p '{"spec":{"runStrategy":"Always"}}'   # 启动
RunStrategy含义
Always保持运行(VMI 异常退出自动重建)
Halted停止(回收 VMI;不存在 Stopped 这个值)
RerunOnFailure失败时重跑,正常关机后不重启
Manual由 start/stop 子资源显式控制
Once只运行一次,退出后不再拉起

4.2 三个必踩的坑(实测)

bash
# ✗ 用 running 停机 → 被 Harvester webhook 拒绝
kubectl patch vm -p '{"spec":{"running":false}}'
# admission webhook "validator.harvesterhci.io" denied the request:
# running and runstrategy are mutually exclusive

# ✗ 写 Stopped → 被 API 拒绝
kubectl patch vm -p '{"spec":{"runStrategy":"Stopped"}}'
# The request is invalid: spec.runStrategy: Invalid RunStrategy (Stopped)

# ✗ json patch 删除并不存在的字段 → 整个请求失败
kubectl patch vm --type=json -p '[{"op":"remove","path":"/spec/running"}]'
# The request is invalid: the server rejected our request due to an error in our request

原因:创建时若写了 running: true,KubeVirt 默认化会补出 runStrategy: Always, 此后 running 字段不再存在,只能操作 runStrategy新建 VM 建议直接用 runStrategy

4.3 停机耗时预期

  • 有 guest agent / 正常 OS:ACPI 优雅关机,数秒至数十秒;
  • 空盘或无 OS:无人响应 ACPI,需等 terminationGracePeriodSeconds(默认 30s)强制终止; 期间 VMI 带 deletionTimestamp 仍显示 Running 属正常:
bash
kubectl get vmi -n default <vm> -o jsonpath='{.status.phase} {.metadata.deletionTimestamp}{"\n"}'

4.4 重启 / 强制重启

bash
# 优雅重启(stop → 等 VMI 回收 → start)
kubectl patch vm -n default <vm> --type=merge -p '{"spec":{"runStrategy":"Halted"}}'
kubectl -n default wait vmi/<vm> --for=delete --timeout=120s 2>/dev/null
kubectl patch vm -n default <vm> --type=merge -p '{"spec":{"runStrategy":"Always"}}'

# 仅重建承载 Pod(不改 VM 定义)
kubectl delete pod -n default -l kubevirt.io/domain=<vm>

5. 镜像与数据导入(CDI)

5.1 四种常用 source

yaml
spec:
  source:
    http:     {url: "https://<内网源>/os.img"}     # HTTP(S) 下载(nbdkit + curl)
    blank:    {}                                   # 空盘(秒级,验证链路用)
    pvc:      {namespace: default, name: <源pvc>}   # 集群内克隆(不走外网,推荐复用)
    registry: {url: "docker://<repo>/<image>"}     # 容器镜像内的磁盘

5.2 生产规范:不要把公网 URL 当镜像源

实测教训(详见 02-故障排查与修复记录.md 案例 13):

nbdkit: curl[1]: error: problem doing HEAD request to fetch size of URL
[https://download.cirros-cloud.net/…/cirros-0.6.2-x86_64-disk.img]:
SSL connect error: Recv failure: Connection reset by peer
→ Conversion to Raw failed → 进度从 99.62% 回退到 2.5%,importer 反复重启(restarts=7)

推荐做法:① 先入库为 Harvester VirtualMachineImage(UI: Images → Create); ② 或搭建内网 HTTP/S3 源;③ 已有卷时用 source.pvc 克隆。

5.3 导入观察与排障命令

bash
kubectl get dv -n default <dv>                       # phase + progress%
kubectl get pod -n default | grep importer           # importer / importer-prime
kubectl logs -n default importer-<> --tail=50       # 当前尝试
kubectl logs -n default importer-<> --previous      # 上一次失败原因
kubectl get dv -n default <dv> -o jsonpath='{.status.conditions[?(@.type=="Bound")].message}'
kubectl get pod -n default importer-<> \
  -o jsonpath='{.status.containerStatuses[0].lastState.terminated.message}'   # ★ 错误最完整

RWX 卷的 populator 流程:CDI 会先生成 prime-<uid> PVC(导入实际写入它)与 prime-<uid>-scratch PVC(转换暂存),目标 PVC 在完成前一直 Pending。 这是正常现象,判断依据是 importer Pod 是否在推进进度,不要误判为卡死。

5.4 导入失败对照表

错误关键字根因处置
SSL connect error: Recv failure: Connection reset by peer外部镜像源不稳定/被限流换内网源;先用 blank/pvc 验证平台
blockdev: cannot open /dev/cdi-block-volume: Permission deniedRWX + Block(Longhorn RWX 无块设备)RWO+BlockRWX+Filesystem
could not create raw image with size … qemu-img execution failedRWX 数据面不可用(无 share-manager)改 RWO;按 02 案例 8 修 Longhorn RWX
进度长时间停在同一百分比后回退网络中断,CDI 自动重试并从头计时看 importer 日志确认,换源
PVC Pending 且无 importer Pod卷未绑定(副本不足/无默认 SC)查节点数、numberOfReplicas、默认 SC

6. 快照与恢复(★ 必读选型)

一句话结论(2026-09-06,4 次重复实测)

  • 快照创建:可用(实测 5~11s 即 phase=Succeeded readyToUse=true)。
  • 快照恢复:当前 type: snap 配置下不可靠,不可用于生产 —— restore 会替换 VM 的 PVC → 源卷被删 → Longhorn Snapshot CR 因 ownerReference 被 GC, 与 full-copy 克隆形成竞态:4 次实测 2 次失败(卷卡 initiated/failed、VM 起不来), 2 次成功但卷遗留 robustness=degraded(3 副本只建出 1 个,冗余受损)。 而控制面始终全绿:complete=truereadyToUse=trueDataVolumesReady=True
  • 要可靠恢复,必须先配 Longhorn backup target 并改用 type: bak(数据在集群外,无竞态)。
  • 完整取证与四次对比见 02-故障排查与修复记录.md 案例 17;数据面核对方法见本节 §6.4。

6.1 前置条件(缺一即失败)

条件检查命令不满足时的报错
featureGates 含 Snapshot单数kubectl -n harvester-system get kubevirt kubevirt -o jsonpath='{.spec.configuration.developerConfiguration.featureGates}'snapshot feature gate not enabled
virt-api 已加载新 gate(改 CR 后需滚动重启)kubectl apply --dry-run=server 探测同上(CR 已改但仍报)
存在 driver 匹配的 VolumeSnapshotClasskubectl get volumesnapshotclasses.snapshot.storage.k8s.io -o wide快照无类可用
类参数语义与 backup target 匹配… longhorn -o jsonpath='{.parameters.type}'backup target default is not available

免落盘快速验证 gate(推荐纳入日常巡检):

bash
cat <<'EOF' | kubectl apply --dry-run=server -f -
apiVersion: snapshot.kubevirt.io/v1beta1
kind: VirtualMachineSnapshot
metadata: {name: gate-probe, namespace: default}
spec:
  source: {apiGroup: kubevirt.io, kind: VirtualMachine, name: __nonexistent__}
EOF
# 报 "snapshot feature gate not enabled" → gate 未生效
# 报 VM not found                        → gate 已生效 ✓

6.2 创建快照

bash
kubectl apply -f scripts/manifests/vm-snapshot.yaml   # apiVersion: snapshot.kubevirt.io/v1beta1
kubectl get virtualmachinesnapshots.snapshot.kubevirt.io -n default <snap> \
  -o jsonpath='{.status.phase} {.status.readyToUse} {.status.error.message}{"\n"}'

实测成功输出:

phase=Succeeded  readyToUse=true  error=<空>
VolumeSnapshot        : class=longhorn  readyToUse=true  restoreSize=2Gi
VolumeSnapshotContent : handle=snap://pvc-63e77fab-…/snapshot-5a993416-…
VM SnapshotContent    : vmsnapshot-content-d1e2c11b-…  readyToUse=true

handle 前缀可判断语义:snap:// = 卷内快照;备份型会是 Longhorn backup 名。

6.3 恢复(目标 VM 必须先停机)

bash
kubectl patch vm -n default <vm> --type=merge -p '{"spec":{"runStrategy":"Halted"}}'
kubectl apply -f scripts/manifests/vm-restore.yaml
kubectl get virtualmachinerestores.snapshot.kubevirt.io -n default <restore> \
  -o jsonpath='{.status.complete} {.status.restores}{"\n"}'
kubectl patch vm -n default <vm> --type=merge -p '{"spec":{"runStrategy":"Always"}}'

实测:complete=trueReady=True:Operation complete,生成新 DV/PVC 并改写 VM 卷引用 ✓

restores=[{dataVolumeName: restore-52856d85-…-disk-0,
           persistentVolumeClaim: restore-52856d85-…-disk-0,
           volumeName: disk-0,
           volumeSnapshotName: vmsnapshot-d1e2c11b-…-volume-disk-0}]

⚠️ 以上全部是控制面信号,与"VM 能否真的起来"无关。 在 type: snap 下即使 complete=true,恢复出的卷也会因源卷被 GC 而不可用(见 §6.4 与 02 案例 17)。 恢复后必须继续执行 §6.4 的数据面核对。

6.4 ⚠️ 恢复后必须验证数据面(血泪教训)

complete=true 不代表 VM 能起来。恢复后务必核对 Longhorn 卷:

bash
PV=$(kubectl get pvc -n default <新pvc> -o jsonpath='{.spec.volumeName}')
kubectl get volumes.longhorn.io -n longhorn-system "$PV" -o jsonpath='
  state={.status.state} robustness={.status.robustness} node={.status.currentNodeID}
  dataSource={.spec.dataSource}
  cloneStatus={.status.cloneStatus}
  replicas={range .status.replicas[*]}{.mode} {end}{"\n"}'

出现以下任一情况即说明恢复出的卷不可用(本环境两次实测踩过):

# 形态 A(源卷已删,克隆直接失败)
state=detached  robustness=unknown  node=<空>  replicas=<空>
dataSource=snap://<源卷>/<快照>
cloneStatus={"attemptCount":0,"sourceVolume":"","state":"failed"}

# 形态 B(更隐蔽:卷"已挂载"但克隆永不收敛)—— 2026-09-06 实测
state=attached  robustness=degraded  node=sza122100.local  replicas=<空>
cloneStatus={"attemptCount":1,"nextAllowedAttemptAt":"…","snapshot":"snapshot-69ceba6a-…",
             "sourceVolume":"pvc-5c8937fb-…","state":"initiated"}
# 同时:replica CR 存在但 spec.mode=<none>;numberOfReplicas=3 却只建出 1 个副本

对应 VM 症状:卡 Scheduling(或 Stopped 起不来),Ready=False reason=GuestNotRunning,事件 AttachVolume.Attach failed … volume … is not ready for workloads

根因(结构性缺陷 + 竞态)type: snap卷内快照,恢复需从源卷做 full-copy 克隆; 而 Longhorn Snapshot CR 的 ownerReference 指向源卷,KubeVirt 恢复又会替换掉原 PVC:

type:snap 快照 → Snapshot CR(ownerRef = 源卷)
   → restore 新建 PVC 并改挂 → 原 PVC/源卷被删除 → GC 级联删除 Snapshot CR
   → 与 full-copy 克隆【竞态】:
      · 拷贝抢先完成 → copy-completed-awaiting-healthy → 卷可用(但常 degraded)
      · GC 抢先      → cloneStatus 卡 initiated / 变 failed → 卷 degraded、副本无模式 → VM 起不来

实测 4 次:2 次失败、2 次成功但卷遗留 degraded。完整取证见 02-故障排查与修复记录.md 案例 17

注意假象:CSI 层 VolumeSnapshot 仍显示 readyToUse=trueVirtualMachineRestorecomplete=true、DV 仍 Succeeded —— 它们都不会因 Longhorn 后端快照被 GC 而回写失败。

规范

  • 需要"可恢复"的快照 → VSC 用 type: bak 且配置 backup target(数据在集群外,不依赖源卷);
  • type: snap 仅用于确定保留源卷的场景(临时回滚点),或只验证到 readyToUse=true 为止;
  • 恢复后必须核对 Longhorn 卷的四元组status.state + status.robustness + status.replicas[*].mode + status.cloneStatus.state
  • DataVolume Succeeded、PVC Bound、VolumeSnapshot readyToUse=true 都是控制面信号, 不能替代数据面核对;
  • scripts/vm-e2e-test.sh 已把该判定自动化:克隆 120s 未收敛时反查源卷是否被删, 并直接给出根因与整改建议。

6.5 删除快照(含卡住处置)

bash
kubectl delete virtualmachinesnapshots.snapshot.kubevirt.io -n default <snap>
# 卡住时(content 因创建失败陷入重试死循环):先修因,再摘 finalizer
kubectl patch volumesnapshotclasses.snapshot.storage.k8s.io longhorn --type=merge -p '{"parameters":{"type":"snap"}}'
kubectl patch volumeSnapshotcontents.snapshot.storage.k8s.io snapcontent-<uid> \
  --type=merge -p '{"metadata":{"finalizers":null}}'
# 实测:content 删除后 VolumeSnapshot 会自动释放,无需单独处理

7. 删除与清理(实测流程)

7.1 标准删除顺序

bash
# 1) 删 VM —— 级联回收 VMI、virt-launcher Pod、DataVolume、PVC、Longhorn 卷
kubectl delete vm -n default <vm> --wait=false

# 2) cloud-init Secret 不会被级联删除,需单独清理
kubectl delete secret -n default <vm>-cloudinit --ignore-not-found

# 3) 若曾做过快照/恢复,清理快照对象
kubectl delete virtualmachinesnapshots.snapshot.kubevirt.io -n default --all --ignore-not-found
kubectl delete virtualmachinerestores.snapshot.kubevirt.io -n default --all --ignore-not-found

harvester-longhornreclaimPolicy: Delete,因此删 PVC 会自动删除 PV 与 Longhorn 卷, 存储空间随之释放(实测清理后 volumes.longhorn.io 为空)。 若希望删 PVC 后保留卷,需另建 reclaimPolicy: Retain 的 StorageClass。

7.2 无残留核查(★ 交付/演练收尾必做)

bash
# 计算面:VM / VMI / DV / PVC / Pod 全部清空
kubectl get vm,vmi,dv,pvc,pod -n default --no-headers
#   期望输出:No resources found in default namespace.

# 数据面:Longhorn 卷已回收(否则仍在占用磁盘)
kubectl get volumes.longhorn.io -n longhorn-system --no-headers
#   期望输出:No resources found in longhorn-system namespace.

# 快照类对象(含 content)
kubectl get volumesnapshots.snapshot.storage.k8s.io -A --no-headers
kubectl get volumesnapshotcontents.snapshot.storage.k8s.io --no-headers
kubectl get virtualmachinesnapshots.snapshot.kubevirt.io -A --no-headers

# 存储容量已归还
kubectl get nodes.longhorn.io -n longhorn-system -o wide   # available 应回升

# 容量水位(应回到基线 ~4.9GB)
kubectl get sc harvester-longhorn -o yaml | grep -E 'numberOfReplicas|dataLocality'

7.3 实测结果(本次清理)

$ kubectl get vm,vmi,dv,pvc,pod -n default --no-headers
No resources found in default namespace.            ✓

$ kubectl get volumes.longhorn.io -n longhorn-system --no-headers
No resources found in longhorn-system namespace.    ✓

说明:删除 VM 即可完整回收计算与存储资源,无需手工清理 Longhorn 卷。

7.4 删除卡住时的处置

现象原因处置
VM 删除后 virt-launcher Pod 仍在优雅终止期 / guest 无响应 ACPI等待 terminationGracePeriodSeconds;必要时 kubectl delete pod --force --grace-period=0
PVC 长期 Terminatingkubernetes.io/pvc-protection 未摘(仍有 Pod 引用)先确认无 Pod 引用;再摘 finalizer
Longhorn 卷残留PV reclaimPolicy: Retain,或卷处于 faultedkubectl delete volumes.longhorn.io -n longhorn-system <vol>
VolumeSnapshotContent 卡住创建失败陷入重试死循环见 §6.5

8. 状态速查表

8.1 VirtualMachine 常见状态

状态含义下一步
ProvisioningDV 创建/导入中kubectl get dv 进度与 importer 日志
DataVolumeErrorDV 导入失败kubectl get dv -o yaml 看 conditions/message
StartingVMI 调度中看 VMI conditions 与 kubectl describe vm 事件
Running正常
Scheduling(长期)卷无法 attach / 资源不足查 Longhorn 卷 state/robustness、节点容量
Stopped / Halted已停机runStrategy=Always 启动

8.2 VMI 状态流转

Scheduling → Scheduled → Running

Scheduling 长期不动时优先查:卷 attach 失败(AttachVolume.Attach failed)、 节点资源不足、nodeSelector 指向不可调度节点。

8.3 DataVolume 进度

phaseprogress说明
ImportScheduled已排队
ImportInProgress递增正常下载/转换中
ImportInProgress回退网络中断后 CDI 重试并从头计时(见 §5.2)
Succeeded100.0%控制面成功(不等于数据面可用,见 §6.4)
Failed失败,看 importer 日志与 DV conditions

8.4 一键体检

bash
bash scripts/healthcheck.sh              # 平台健康度(约 20s)
bash scripts/vm-e2e-test.sh              # VM 全生命周期端到端验证(创建→迁移→快照→清理)