主题
Rocky 9 VM 部署操作日志 — 2026-08-27
目标: 在 KubeVirt 集群 (RKE2, 6 节点, Rocky Linux 9.8) 上通过 hostPath PV 启动一个 Rocky Linux 9 虚拟机。 结果: ✅ 成功。VM
rocky9-test运行中,SSH 可达。
目录
1. 环境信息
| 项目 | 值 |
|---|---|
| 集群 | RKE2 v1.35.6 |
| 节点数 | 6 (1 master, 5 worker) |
| 节点 OS | Rocky Linux 9.8 |
| 容器网络 | Calico VXLAN (CNI) |
| 镜像仓库 | Harbor 192.168.122.156:30000 (代理 quay.io/kubevirt) |
| KubeVirt 版本 | v1.9.0 |
| virt-operator | 2 副本, Running |
| virt-controller | 2 副本, Running |
| virt-handler | DaemonSet, 6 节点 |
| 工作节点 (目标) | sza122031.local |
| 镜像源 | http://192.168.122.9:9001/repo/osiso/ |
2. 磁盘镜像准备
2.1 下载 qcow2
bash
# 在目标节点 sza122031.local 执行
curl -Lo /tmp/Rocky-9-GenericCloud.qcow2 \
http://192.168.122.9:9001/repo/osiso/Rocky-9-GenericCloud-Base.latest.x86_64.qcow2- 文件大小: ~630 MB (qcow2 压缩格式)
- 格式: QCOW2 (QEMU Copy-On-Write v2)
2.2 转换为 raw 格式
bash
dnf install -y qemu-img # 如果没有安装
qemu-img convert -f qcow2 -O raw \
/tmp/Rocky-9-GenericCloud.qcow2 \
/tmp/Rocky-9-GenericCloud.raw- 原始大小: 10 GiB (raw 格式)
- 转换时间: 约 30 秒
2.3 放置到 KubeVirt 期望的目录结构
KubeVirt hostPath PVC 要求:
- PV 的
hostPath.path指向一个目录 - 目录中必须有一个名为
disk.img的文件 - 不能直接指向文件路径
bash
mkdir -p /var/lib/vm-images/rocky9-disk
mv /tmp/Rocky-9-GenericCloud.raw /var/lib/vm-images/rocky9-disk/disk.img
chmod 666 /var/lib/vm-images/rocky9-disk/disk.img
# 验证
ls -la /var/lib/vm-images/rocky9-disk/
# total 10485764
---
## 3. PV/PVC 创建
### 3.1 PersistentVolume
```yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: rocky9-vm-disk
labels:
type: rocky9-disk
spec:
storageClassName: manual
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/var/lib/vm-images/rocky9-disk" # 指向目录,不是文件!
type: Directory
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- sza122031.local3.2 PersistentVolumeClaim
yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: rocky9-vm-disk
namespace: default
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
selector:
matchLabels:
type: rocky9-disk3.3 验证绑定
bash
kubectl get pv rocky9-vm-disk
# NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS BOUND
# rocky9-vm-disk 10Gi RWO Retain Bound
kubectl get pvc rocky9-vm-disk -n default
# NAME STATUS VOLUME CAPACITY ACCESS MODES
# rocky9-vm-disk Bound rocky9-vm-disk 10Gi RWO4. VM 创建与故障排查
4.1 初始 VM 定义
yaml
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
name: rocky9-test
namespace: default
labels:
app: rocky9-test
kubevirt.io/vm: rocky9-test
spec:
running: true
template:
metadata:
labels:
app: rocky9-test
kubevirt.io/vm: rocky9-test
spec:
nodeSelector:
kubernetes.io/hostname: sza122031.local
domain:
cpu:
cores: 2
memory:
guest: 2Gi
devices:
disks:
- name: rootdisk
disk:
bus: virtio
- name: cloudinit
disk:
bus: virtio
interfaces:
- name: default
masquerade: {}
networks:
- name: default
pod: {}
volumes:
- name: rootdisk
persistentVolumeClaim:
claimName: rocky9-vm-disk
- name: cloudinit
cloudInitNoCloud:
userData: |
#cloud-config
hostname: rocky9-test
password: xxx
chpasswd:
expire: false
ssh_pwauth: true
disable_root: false创建后 VMI 一直卡在 Scheduling 阶段。以下是按排查顺序记录的四个问题:
问题 1: virt-handler 证书缺失
症状:
bash
kubectl logs -n kubevirt -l kubevirt.io=virt-handler -c virt-handler --tail=5
# ERROR: failed to load the certificate /etc/virt-handler/clientcertificates/tls.crt分析过程:
- virt-handler 需要通过 gRPC 与 virt-launcher Pod 通信
- gRPC 需要 mTLS 双向认证
- virt-handler DaemonSet 未挂载
kubevirt-virt-handler-certsSecret - 尝试
customizeComponentspatch → 被 virt-operator 覆盖 - 尝试直接修改 DaemonSet → 同样被覆盖
解决方案 (临时):
bash
# 从 Secret 提取证书
kubectl get secret kubevirt-virt-handler-certs -n kubevirt \
-o jsonpath='{.data.tls\.crt}' | base64 -d > /tmp/handler.crt
kubectl get secret kubevirt-virt-handler-certs -n kubevirt \
-o jsonpath='{.data.tls\.key}' | base64 -d > /tmp/handler.key
# 复制到 virt-handler Pod
POD=$(kubectl get pods -n kubevirt -l kubevirt.io=virt-handler \
-o jsonpath='{.items[0].metadata.name}')
kubectl exec -n kubevirt $POD -c virt-handler -- \
mkdir -p /etc/virt-handler/clientcertificates
kubectl cp /tmp/handler.crt kubevirt/$POD:/etc/virt-handler/clientcertificates/tls.crt \
-c virt-handler
kubectl cp /tmp/handler.key kubevirt/$POD:/etc/virt-handler/clientcertificates/tls.key \
-c virt-handler⚠️ 注意: 此修复在 virt-handler Pod 重启后失效,需重新执行。
问题 2: CDI CRD 存根干扰
症状:
bash
kubectl logs -n kubevirt -l kubevirt.io=virt-controller -c virt-controller --tail=5
# Failed to get filesystem overhead for PVC default/rocky9-vm-disk
# CDI config not initialized分析过程:
- virt-controller 启动时检测到 CDI CRD 存在
- 尝试通过 CDIConfig API 获取文件系统开销比例
- 但 CDI 只有 CRD 没有完整部署 (之前尝试过 CDI 但未成功)
- 导致 virt-controller 一直 re-enqueue VMI
解决方案:
bash
# 删除所有 CDI 相关空壳 CRD
kubectl delete crd cdiconfigs.cdi.kubevirt.io
kubectl delete crd cdis.cdi.kubevirt.io
kubectl delete crd datavolumes.cdi.kubevirt.io
kubectl delete crd storageprofiles.cdi.kubevirt.io
kubectl delete crd datasources.cdi.kubevirt.io
kubectl delete crd dataimportcrons.cdi.kubevirt.io
kubectl delete crd objecttransfers.cdi.kubevirt.io
kubectl delete crd uploadtokenrequests.cdi.kubevirt.io
kubectl delete crd volumeimportsources.cdi.kubevirt.io
kubectl delete crd volumeuploadsources.cdi.kubevirt.io
kubectl delete ns cdi
# 重启 virt-controller 使其重新评估
kubectl delete pods -n kubevirt -l kubevirt.io=virt-controller📌 关键发现: virt-controller 在启动时检测 CRD 列表。如果 CDI CRD 存在, 它就假设 CDI 已部署并尝试使用 CDIConfig API。删除 CRD 后重启 virt-controller 可让它在启动时跳过 CDI 集成逻辑。
问题 3: EvictionStrategy 冲突
症状:
bash
kubectl get events -n default --sort-by=.lastTimestamp | tail -5
# Warning Migrated vmi/rocky9-test
# EvictionStrategy is set but vmi is not migratable;
# cannot migrate VMI: PVC rocky9-vm-disk is not shared,
# live migration requires that all PVCs must be shared
# (using ReadWriteMany access mode)分析过程:
- KubeVirt CR 中配置了全局
evictionStrategy: LiveMigrate - hostPath PV 是 ReadWriteOnce,不支持 LiveMigration
- KubeVirt 发现无法迁移但仍尝试,导致 VMI 被驱逐
解决方案:
bash
# 方法 A: 在 VM 级别覆盖 (推荐)
# 在 VM spec.template.spec 中添加:
evictionStrategy: None
# 方法 B: 修改全局 KubeVirt CR (影响所有 VM)
kubectl patch kv kubevirt -n kubevirt --type=merge \
-p '{"spec":{"configuration":{"evictionStrategy":"None"}}}'📌 我们在 VM 定义和全局 CR 中都设置了
None。
问题 4: 磁盘权限 Permission denied
症状:
bash
kubectl get events -n default --sort-by=.lastTimestamp | tail -5
# Warning SyncFailed vmi/rocky9-test
# LibvirtError(Code=1, Domain=10, Message='internal error: process exited
# while connecting to monitor: qemu-kvm: -blockdev {...}:
# Could not open '/var/run/kubevirt-private/vmi-disks/rootdisk/disk.img':
# Permission denied')分析过程:
- virt-handler 成功将 hostPath 挂载到 virt-launcher Pod
- 挂载路径:
/var/run/kubevirt-private/vmi-disks/rootdisk/disk.img - 实际上是 bind-mount 到
/var/lib/vm-images/rocky9-disk/disk.img - QEMU 进程以 UID 107 (qemu 用户) 运行
- 文件权限:
-rw-------(600),只有 root 可读
解决方案:
bash
# 方案 1: 修改文件权限 (简单直接)
chmod 666 /var/lib/vm-images/rocky9-disk/disk.img
# 验证
ls -la /var/lib/vm-images/rocky9-disk/disk.img
# -rw-rw-rw-. 1 root root 10737418240 Aug 27 11:14 disk.img📌 另一个常见错误: PV 的 hostPath 直接指向文件 (type: File) 而不是目录。 KubeVirt 期望 hostPath 指向一个目录,目录内有
disk.img文件。 如果 PV 直接指向文件路径,KubeVirt 会尝试在文件路径下查找disk.img, 导致找不到文件。
5. 最终验证
5.1 VM 状态
bash
kubectl get vm,vmi -n defaultNAME AGE STATUS READY
virtualmachine.kubevirt.io/rocky9-test 5m4s Running True
NAME AGE PHASE IP NODENAME READY
virtualmachineinstance.kubevirt.io/rocky9-test 3m58s Running 10.22.183.219 sza122031.local True5.2 Libvirt 虚拟机状态
bash
kubectl exec -n default virt-launcher-rocky9-test-vblnz -c compute -- virsh list --all Id Name State
-------------------------------------
1 default_rocky9-test running5.3 网络连通性
bash
ping -c 2 10.22.183.21964 bytes from 10.22.183.219: icmp_seq=1 ttl=63 time=1.16 ms
64 bytes from 10.22.183.219: icmp_seq=2 ttl=63 time=0.366 ms5.4 SSH 登录
bash
sshpass -p rocky ssh -o StrictHostKeyChecking=no \
-o PreferredAuthentications=password \
rocky@10.22.183.219 "hostname && uname -a"rocky9-test
Linux rocky9-test 5.14.0-687.10.1.el9_8.0.1.x86_64 #1 SMP PREEMPT_DYNAMIC Sun May 24 12:01:19 UTC 2026 x86_64 x86_64 x86_64 GNU/Linux5.5 系统信息
bash
sshpass -p rocky ssh rocky@10.22.183.219 "cat /etc/os-release | grep PRETTY_NAME && free -h | head -2 && df -h / | tail -1"PRETTY_NAME="Rocky Linux 9.8 (Blue Onyx)"
total used free shared buff/cache available
Mem: 1.7Gi 301Mi 1.3Gi 4.0Mi 236Mi 1.4Gi
/dev/vda4 8.9G 1009M 7.9G 12% /5.6 Cloud-init 执行日志
从 virt-launcher 的 guest-console-log 容器获取:
Cloud-init v. 24.4-8.el9.rocky.0.1 finished at Thu, 27 Aug 2026 11:42:57 +0000.
Datasource DataSourceNoCloud [seed=/dev/vdb]. Up 54.24 seconds
Rocky Linux 9.8 (Blue Onyx)
Kernel 5.14.0-687.10.1.el9_8.0.1.x86_64 on x86_64
rocky9-test login:5.7 停止/重启测试
bash
# 停止
kubectl patch vm rocky9-test -n default --type merge \
-p '{"spec":{"running":false}}'
# 启动
kubectl patch vm rocky9-test -n default --type merge \
-p '{"spec":{"running":true}}'停止后 VMI 被删除 (~10秒),重新启动后 VMI 重新创建并进入 Running (~30秒)。
6. VM 配置清单
| 属性 | 值 |
|---|---|
| VM 名称 | rocky9-test |
| 命名空间 | default |
| OS | Rocky Linux 9.8 (Blue Onyx) |
| 内核 | 5.14.0-687.10.1.el9_8.0.1.x86_64 |
| CPU | 2 cores |
| 内存 | 2 GiB |
| 磁盘 | 10 GiB (virtio, 实际可用 8.9G) |
| 网络 | Pod 网络 (masquerade) |
| VMI IP | 10.22.183.219 (DHCP, 可能变化) |
| SSH 用户 | rocky |
| SSH 密码 | xxx |
| root 密码 | 未设置 (cloud-init 仅设置了 rocky 用户) |
| 节点 | sza122031.local (固定) |
| PV 路径 | /var/lib/vm-images/rocky9-disk/ |
| 镜像文件 | disk.img (10 GiB raw) |
| Eviction | None (不支持 LiveMigrate) |
7. 经验总结
7.1 KubeVirt hostPath PVC 的正确用法
正确 ✅:
PV hostPath.path: "/var/lib/vm-images/rocky9-disk"
PV hostPath.type: "Directory"
目录内容: disk.img
错误 ❌:
PV hostPath.path: "/var/lib/vm-images/rocky9-disk/disk.img"
PV hostPath.type: "File"7.2 KubeVirt 启动流程 (VMI 生命周期)
VM (running: true)
→ virt-controller 创建 VMI
→ virt-controller 调度 VMI 到节点
→ virt-handler 检测到调度
→ virt-handler 创建 virt-launcher Pod
→ virt-launcher 挂载 PVC (hostPath → /var/run/kubevirt-private/vmi-disks/rootdisk/)
→ QEMU 启动 (读取 disk.img)
→ Guest OS boot
→ cloud-init 执行
→ VMI 进入 Running phase7.3 常见问题排查命令
bash
# 1. 检查 VMI 阶段和事件
kubectl get vmi -n default
kubectl describe vmi rocky9-test -n default
# 2. 检查 virt-controller 日志 (调度/CDI 问题)
kubectl logs -n kubevirt -l kubevirt.io=virt-controller \
-c virt-controller --tail=20
# 3. 检查 virt-handler 日志 (节点级问题)
kubectl logs -n kubevirt -l kubevirt.io=virt-handler \
-c virt-handler --tail=20
# 4. 检查 virt-launcher 日志 (QEMU/libvirt 问题)
kubectl logs -n default -l kubevirt.io=virt-launcher \
-c compute --tail=20
# 5. 查看 Guest 控制台输出 (boot 日志)
kubectl logs -n default -l kubevirt.io=virt-launcher \
-c guest-console-log --tail=50
# 6. 检查 Libvirt 虚拟机状态
POD=$(kubectl get pods -n default -l kubevirt.io=virt-launcher \
-o jsonpath='{.items[0].metadata.name}')
kubectl exec -n default $POD -c compute -- virsh list --all
# 7. 检查已安装的 CRD
kubectl get crd | grep -E '(kubevirt|cdi)'7.4 virt-handler 证书修复脚本
每次 virt-handler Pod 重启后执行:
bash
#!/bin/bash
# fix-virt-handler-certs.sh
# 修复 virt-handler clientcertificates 缺失问题
set -e
echo "提取证书..."
kubectl get secret kubevirt-virt-handler-certs -n kubevirt \
-o jsonpath='{.data.tls\.crt}' | base64 -d > /tmp/handler.crt
kubectl get secret kubevirt-virt-handler-certs -n kubevirt \
-o jsonpath='{.data.tls\.key}' | base64 -d > /tmp/handler.key
for POD in $(kubectl get pods -n kubevirt -l kubevirt.io=virt-handler \
-o jsonpath='{.items[*].metadata.name}'); do
echo "修复 $POD..."
kubectl exec -n kubevirt $POD -c virt-handler -- \
mkdir -p /etc/virt-handler/clientcertificates
kubectl cp /tmp/handler.crt \
kubevirt/$POD:/etc/virt-handler/clientcertificates/tls.crt \
-c virt-handler
kubectl cp /tmp/handler.key \
kubevirt/$POD:/etc/virt-handler/clientcertificates/tls.key \
-c virt-handler
echo " ✓ $POD 已修复"
done
rm -f /tmp/handler.crt /tmp/handler.key
echo "完成!"7.5 下一步计划
- CDI 完整部署: 安装 CDI Operator,支持 DataVolume 自动下载/转换镜像
- 多 VM 模板: 创建 VM template 支持快速克隆部署
- 存储升级: 配置 NFS/Longhorn 支持 ReadWriteMany + LiveMigration
- SSH Service: 创建 NodePort/LoadBalancer Service 暴露 SSH 端口
- virt-handler 证书永久修复: 等待 KubeVirt 上游修复或创建 initContainer
- 批量 VM 管理: 通过 Web UI 或脚本管理 VM 生命周期
8. rocky9-vm2 部署记录 (第二台 VM)
8.1 部署概要
| 项目 | 值 |
|---|---|
| VM 名称 | rocky9-vm2 |
| OS | Rocky Linux 9.8 (Blue Onyx) |
| CPU | 2 cores |
| 内存 | 2Gi |
| 磁盘 | 10Gi (hostPath PV) |
| 网络 | Pod 网络 (masquerade) |
| VMI IP | 10.22.183.231 |
| SSH 用户 | rocky |
| SSH 密码 | xxx |
| 节点 | sza122031.local (固定) |
| PV 路径 | /var/lib/vm-images/rocky9-vm2-disk/ |
| 镜像文件 | disk.img (10 GiB raw) |
| 状态 | ✅ Running |
8.2 遇到的问题和解决
| # | 问题 | 原因 | 解决方案 |
|---|---|---|---|
| 1 | 节点 sza122031.local 内存不足 | 多个 stuck/terminating pods 占用内存 | kubectl delete pod --force --grace-period=0 强制删除 |
| 2 | API Server 端口 6443 无法连接 | etcd crash loop, kube-apiserver 反复重启 | 使用备用 API endpoint (192.168.122.23:6443 via /tmp/rke2-23.yaml) |
| 3 | VMI 调度失败: "FailedScheduling" | 节点 not-ready, kubevirt.io/schedulable=false | 等待节点恢复 Ready 状态 |
| 4 | virt-launcher pod 卡在 Pending | 节点不稳定, kubelet 无法处理 pod | 节点恢复后自动重建 |
| 5 | virt-handler pod Unknown 状态 | RKE2 重启后旧 pod 状态不同步 | kubectl delete pod --force 让 DaemonSet 重建 |
| 6 | 节点 label kubevirt.io/schedulable=false | virt-handler 未正常运行标记节点 | 重建 virt-handler pod 后自动修复 |
8.3 最终状态
bash
$ kubectl get vm rocky9-vm2 -n default
NAME AGE STATUS READY
rocky9-vm2 19m Running True
$ kubectl get vmi rocky9-vm2 -n default
NAME AGE PHASE IP NODENAME READY
rocky9-vm2 3m Running 10.22.183.231 sza122031.local True
$ ssh rocky@10.22.183.231 # password: xxx
=== VM BOOT SUCCESSFUL ===
rocky9-vm2
NAME="Rocky Linux"
VERSION="9.8 (Blue Onyx)"
=== UPTIME ===
14:39:43 up 2 min
=== MEMORY ===
total used free shared buff/cache available
Mem: 1.7Gi 318Mi 1.3Gi 4.0Mi 236Mi 1.4Gi
=== DISK ===
Filesystem Size Used Avail Use% Mounted on
/dev/vda4 8.9G 1009M 7.9G 12% /8.4 关键操作时间线
| 时间 (UTC) | 事件 |
|---|---|
| 14:17 | VM 和 VMI 创建成功 |
| 14:17~14:25 | 节点内存不足, API Server 不可达 |
| 14:25 | 强制删除 stuck pods, 释放内存 |
| 14:28 | 节点恢复 Ready, etcd 连接成功 |
| 14:30 | kube-apiserver (port 6443) 恢复 |
| 14:33 | virt-handler pod 重建并标记节点 schedulable=true |
| 14:33 | 新的 virt-launcher pod 创建并启动 |
| 14:36 | VMI 进入 Running 阶段, Guest Agent 连接 |
| 14:39 | SSH 登录成功, VM 完全可用 |
9. rocky9-vm3 部署记录 (第三台 VM — containerDisk 在线资源)
9.1 部署概要
| 项目 | 值 |
|---|---|
| VM 名称 | rocky9-vm3 |
| OS | Rocky Linux 9.8 (Blue Onyx) |
| CPU | 2 cores |
| 内存 | 2Gi |
| 磁盘方式 | containerDisk (在线 OCI 镜像,无需 hostPath PV) |
| containerDisk 镜像 | 192.168.122.156:30000/kubevirt-local/rocky9-containerdisk:v9.8 |
| 网络 | Pod 网络 (masquerade) |
| VMI IP | 10.22.14.81 |
| SSH 用户 | rocky |
| SSH 密码 | xxx |
| 节点 | sza122031.local (调度) |
| 状态 | ✅ Running |
9.2 containerDisk 方案 vs hostPath PV 对比
| 维度 | hostPath PV (vm1/vm2) | containerDisk (vm3) |
|---|---|---|
| 磁盘准备 | 需手动在每个节点放置 disk.img | 镜像存入 Harbor,按需拉取 |
| PV/PVC | 需要创建 PV 和 PVC | 不需要 |
| 节点绑定 | 必须 nodeSelector 固定节点 | 可调度到任意节点 |
| 部署复杂度 | 需 3 个资源 (PV + PVC + VM) | 仅需 1 个 VM YAML |
| 镜像来源 | 本地文件 | Harbor OCI 镜像 |
| 适合场景 | 单节点/测试 | 多节点/生产 |
9.3 OCI 镜像构建过程
使用 skopeo 将 qcow2 磁盘镜像打包为 OCI 镜像并推送到 Harbor:
bash
# 1. 下载 qcow2 源镜像 (617MB)
curl -Lo /tmp/Rocky-9-GenericCloud.qcow2 \
http://192.168.122.9:9001/repo/osiso/Rocky-9-GenericCloud-Base.latest.x86_64.qcow2
# 2. 构建 OCI image layout
mkdir -p /tmp/oci-build/disk /tmp/oci-build/blobs/sha256
cp /tmp/Rocky-9-GenericCloud.qcow2 /tmp/oci-build/disk/disk.img
# 3. 创建 layer tarball
tar -C /tmp/oci-build -cf /tmp/oci-build/layer.tar disk/
# 4. 计算 SHA256 并组装 OCI manifest/config
LAYER_SHA=$(sha256sum /tmp/oci-build/layer.tar | awk '{print $1}')
# ... (构建 config.json, manifest.json, index.json, oci-layout)
# 5. 推送到 Harbor
skopeo copy --dest-tls-verify=false \
--dest-creds "admin:xxx" \
oci:/tmp/oci-build:v9.8 \
docker://192.168.122.156:30000/kubevirt-local/rocky9-containerdisk:v9.89.4 遇到的问题和解决
| # | 问题 | 原因 | 解决方案 |
|---|---|---|---|
| 1 | skopeo push unauthorized | 使用了错误密码 xxx | 从文档找到正确密码 xxx |
| 2 | skopeo push denied: proxy project | kubevirt 项目是 proxy 类型,不能直接 push | 改用 kubevirt-local 普通项目 |
| 3 | ImagePullBackOff: HTTP vs HTTPS | 节点 containerd hosts.toml 配置 server = "https://..." 但 Harbor 是 HTTP | `sed -i 's |
| 4 | VM spec imagePullSecrets 字段错误 | KubeVirt 不支持 spec.template.spec.imagePullSecrets | 改用 containerDisk.imagePullSecret 字段 |
9.5 最终状态
bash
$ kubectl get vm rocky9-vm3 -n default
NAME AGE STATUS READY
rocky9-vm3 3m36s Running True
$ kubectl get vmi rocky9-vm3 -n default -o wide
NAME AGE PHASE IP NODENAME READY LIVE-MIGRATABLE
rocky9-vm3 116s Running 10.22.14.81 sza122031.local True True
$ ssh rocky@10.22.14.81 # password: xxx
rocky9-vm3
NAME="Rocky Linux"
VERSION="9.8 (Blue Onyx)"
inet 10.0.2.2/24 brd 10.0.2.255 scope global dynamic noprefixroute eth09.6 关键操作时间线
| 时间 (UTC) | 事件 |
|---|---|
| 14:47 | 开始在 192.168.122.31 构建 OCI 镜像 |
| 15:01 | OCI layer tarball 完成 (342MB → 526MB → 完成) |
| 15:01 | OCI manifest/config 生成完成 |
| 15:01 | 首次推送失败: unauthorized (密码错误) |
| 15:03 | 使用正确密码推送到 kubevirt 项目失败: proxy project |
| 15:04 | 推送到 kubevirt-local 项目成功 |
| 15:05 | 创建 VM, 调度到 sza122023.local, ImagePullBackOff |
| 15:06 | 修复所有可访问节点 hosts.toml: https → http |
| 15:07 | 删除失败 Pod, 重新调度 |
| 15:08 | 新 Pod 拉取镜像成功, Init 阶段 |
| 15:09 | VM 状态 Running=True, VMI Running |
| 15:10 | SSH 登录成功, VM 完全可用 |
9.7 注意事项
- Harbor 密码:
xxx(记录在15-harbor-admin-密码重置实战.md) - kubevirt 项目是 proxy 类型: 只能做镜像代理,不能直接推送镜像。推送用
kubevirt-local。 - hosts.toml 会被 RKE2 覆盖: 如果 RKE2 重启,hosts.toml 会重新生成为 HTTPS。需要修改 registries.yaml 中的
configs段去掉tls配置,或在 RKE2 重启后再次修复。 - 未修复的节点: 192.168.122.28 和 192.168.122.29 SSH 不通,未修复 hosts.toml。如果 VM 调度到这两个节点会拉取失败。
日志记录时间: 2026-08-27
操作人: AI Agent (自动化部署)