Skip to content

K3s + KubeVirt 部署与运维指南

部署日期: 2026-08-26 目标: 在 K3s 单节点集群上部署 KubeVirt,实现 libvirt VM 向容器化虚拟机的迁移。 服务器: yi (192.168.1.111, SSH 端口 6022, 用户 zai)


目录

  1. 集群架构概览
  2. 核心组件部署状态
  3. 关键问题与解决方案
  4. KubeVirt Web UI
  5. VM 管理命令速查
  6. VM 迁移计划 (libvirt → KubeVirt)
  7. 服务访问地址
  8. 附录:配置文件与路径

1. 集群架构概览

┌─────────────────────────────────────────────────────────┐
│  宿主机 (yi / 192.168.1.111)                            │
│                                                         │
│  ┌───────────────────────────────────────────────────┐  │
│  │  K3s 集群                                          │  │
│  │                                                   │  │
│  │  ┌─────────┐ ┌─────┐ ┌────────┐ ┌─────────────┐ │  │
│  │  │KubeVirt │ │ CDI │ │Multus  │ │ HAMi GPU    │ │  │
│  │  │ v1.9.0  │ │v1.66│ │(flannel│ │ (GTX1060)   │ │  │
│  │  │ 9 pods  │ │4 pod│ │ +bridge│ │  2 pods     │ │  │
│  │  └─────────┘ └─────┘ └────────┘ └─────────────┘ │  │
│  │                                                   │  │
│  │  ┌─────────┐ ┌──────────┐ ┌──────────────────┐  │  │
│  │  │ Ollama  │ │Open-WebUI│ │ Traefik Ingress  │  │  │
│  │  │(GPU AI) │ │ (Chat)   │ │                  │  │  │
│  │  └─────────┘ └──────────┘ └──────────────────┘  │  │
│  └───────────────────────────────────────────────────┘  │
│                                                         │
│  ┌─────────────────────┐  ┌─────────────────────────┐  │
│  │ KubeVirt Web UI     │  │ 宿主机 libvirt (待迁移) │  │
│  │ (systemd, :8080)    │  │ Harbor / Jumpserver      │  │
│  └─────────────────────┘  └─────────────────────────┘  │
└─────────────────────────────────────────────────────────┘

节点信息

  • OS: Ubuntu 20.04 (K3s)
  • CPU: 多核
  • GPU: NVIDIA GTX 1060 6GB (HAMi 管理)
  • containerd: K3s 内置

2. 核心组件部署状态

KubeVirt v1.9.0 (虚拟机管理)

安装命令:

bash
export RELEASE=$(curl -s https://api.github.com/repos/kubevirt/kubevirt/releases/latest | grep tag_name | cut -d '"' -f 4)
kubectl apply -f https://github.com/kubevirt/kubevirt/releases/download/${RELEASE}/kubevirt-operator.yaml
kubectl apply -f https://github.com/kubevirt/kubevirt/releases/download/${RELEASE}/kubevirt-cr.yaml
Pod状态说明
virt-operator (x2)✅ Running管理 KubeVirt 生命周期
virt-api (x1)✅ RunningAPI Server
virt-controller (x2)✅ RunningVM 控制器
virt-handler (x1)✅ Running节点级 VM 管理
virt-template-*✅ Running模板服务
virt-exportproxy (x2)✅ Running数据导出代理

CDI v1.66.0 (容器磁盘导入)

安装命令:

bash
export TAG=$(curl -s https://api.github.com/repos/kubevirt/containerized-data-importer/releases/latest | grep '"tag_name"' | cut -d '"' -f 4)
kubectl apply -f https://github.com/kubevirt/containerized-data-importer/releases/download/$TAG/cdi-operator.yaml
kubectl apply -f https://github.com/kubevirt/containerized-data-importer/releases/download/$TAG/cdi-cr.yaml
Pod状态说明
cdi-operator✅ RunningCDI 生命周期管理
cdi-apiserver✅ RunningAPI 服务
cdi-deployment✅ Running数据导入控制器
cdi-uploadproxy✅ Running上传代理

Multus (多网络)

Pod状态说明
kube-multus-ds✅ RunningCNI 多网络插件

HAMi (GPU 虚拟化)

Pod状态说明
hami-device-plugin✅ RunningGPU 设备插件
hami-scheduler✅ RunningGPU 调度器

应用层

Pod状态说明
ollama✅ RunningAI 模型服务 (GPU 5000MB)
open-webui✅ RunningAI 聊天界面

3. 关键问题与解决方案

3.1 镜像拉取失败 — registries.yaml 不生效

现象: 修改 /etc/rancher/k3s/registries.yaml 后,Pod 仍然从旧源拉取镜像,超时失败。

根因: K3s 不会热重载 registries.yaml。修改配置后,containerd 的 hosts.toml 不会自动更新。

解决方案:

bash
# 1. 编辑 registries.yaml
sudo vim /etc/rancher/k3s/registries.yaml

# 2. 重启 K3s 使配置生效
sudo systemctl restart k3s

# 3. 验证 hosts.toml 已更新
sudo cat /var/lib/rancher/k3s/agent/etc/containerd/certs.d/*/hosts.toml

推荐镜像源 (NJU 南京大学):

yaml
mirrors:
  docker.io:
    endpoint:
      - "https://docker.nju.edu.cn"
  quay.io:
    endpoint:
      - "https://quay.nju.edu.cn"
  ghcr.io:
    endpoint:
      - "https://ghcr.nju.edu.cn"
  registry.k8s.io:
    endpoint:
      - "https://k8s.nju.edu.cn"

⚠️ 注意: 每次修改 registries.yaml 后必须 systemctl restart k3s,否则无效!

3.2 Multus CNI 崩溃 — 配置路径不匹配

现象: Multus DaemonSet Pod 报 CrashLoopBackOff,日志显示找不到 CNI 配置。

根因: K3s 将 flannel CNI 配置写入 /var/lib/rancher/k3s/agent/etc/cni/net.d/,而标准 Multus DaemonSet 挂载的是 /etc/cni/net.d/

解决方案:

bash
# 复制 K3s flannel 配置到标准路径
sudo cp /var/lib/rancher/k3s/agent/etc/cni/net.d/10-flannel.conflist /etc/cni/net.d/

# 重启 Multus Pod
kubectl delete pod -n kube-system -l app=multus

3.3 HAMi GPU 调度 Pending — 内存请求超限

现象: Ollama Pod 一直 Pending,调度器报 insufficient nvidia.com/gpumem

根因: GTX1060 显存 6GB,HAMi 报告总显存 6000MB,请求 6000MB 时没有预留系统余量。

解决方案: 将 GPU 内存请求从 6000MB 降至 5000MB:

yaml
resources:
  requests:
    nvidia.com/gpu: "1"
    nvidia.com/gpumem: "5000"    # 预留 1000MB 给系统
  limits:
    nvidia.com/gpu: "1"
    nvidia.com/gpumem: "5000"

3.4 virtctl 安装

bash
export VERSION=$(curl -s https://api.github.com/repos/kubevirt/kubevirt/releases/latest | grep tag_name | cut -d '"' -f 4)
curl -L -o virtctl https://github.com/kubevirt/kubevirt/releases/download/${VERSION}/virtctl-${VERSION}-linux-amd64
chmod +x virtctl
sudo mv virtctl /usr/local/bin/

# 配置 KUBECONFIG
echo 'export KUBECONFIG=/etc/rancher/k3s/k3s.yaml' >> ~/.bashrc
source ~/.bashrc

3.5 镜像拉取速度监控

实时监控 containerd 下载进度的脚本:

bash
sudo bash -c 'while true; do
  for d in /var/lib/rancher/k3s/agent/containerd/io.containerd.content.v1.content/ingest/*/; do
    [ -d "$d" ] || continue
    ref=$(cat ${d}ref 2>/dev/null | sed "s|k8s.io/1/layer-sha256:||;s|.*:||")
    dl=$(stat -c%s ${d}data 2>/dev/null)
    total=$(cat ${d}total 2>/dev/null)
    [ -n "$total" ] && [ "$total" -gt 0 ] && pct=$(( dl * 100 / total )) || pct=0
    echo "${ref:0:12}: ${pct}% ($(( dl / 1048576 ))/$(( total / 1048576 ))MB)"
  done
  sleep 3; echo "---"
done'

4. KubeVirt Web UI

部署方式: systemd + Python 后端

由于 docker.io 镜像拉取极慢(~50KB/s),选择在宿主机直接运行 Python HTTP 服务, 通过 kubectl/virtctl 调用 K8s API,避免拉取额外容器镜像。

文件结构

/opt/kubevirt-ui/
├── server.py          # Python API 后端 (调用 kubectl/virtctl)
└── index.html         # 前端 SPA 页面 (纯 HTML/JS/CSS)

/etc/systemd/system/
└── kubevirt-ui.service  # systemd 服务单元

systemd 服务配置

ini
[Unit]
Description=KubeVirt Web UI
After=network.target

[Service]
Type=simple
User=root
Environment=KUBECONFIG=/etc/rancher/k3s/k3s.yaml
Environment=PORT=8080
ExecStart=/usr/bin/python3 /opt/kubevirt-ui/server.py
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target

API 端点

方法路径说明
GET/前端页面
GET/api/health健康检查
GET/api/vms列出所有 VM
GET/api/vmis列出所有 VMI
GET/api/nodes列出节点
GET/api/pvcs列出 PVC
GET/api/dvs列出 DataVolume
GET/api/vm/{ns}/{name}查看单个 VM
POST/api/vm/{ns}/{name}/start启动 VM
POST/api/vm/{ns}/{name}/stop停止 VM
POST/api/vm/{ns}/{name}/restart重启 VM
POST/api/vm/{ns}/{name}/migrate迁移 VM
POST/api/vm/{ns}/{name}/pause暂停 VM
POST/api/vm/{ns}/{name}/unpause恢复 VM
POST/api/vm/{ns}/{name}/delete删除 VM
POST/api/vm/create创建 VM

管理命令

bash
sudo systemctl status kubevirt-ui     # 查看状态
sudo systemctl restart kubevirt-ui    # 重启
sudo systemctl stop kubevirt-ui       # 停止
sudo systemctl start kubevirt-ui      # 启动
sudo journalctl -u kubevirt-ui -f     # 实时日志

前端功能

  • 📊 集群概览:VM 总数、运行中、已停止
  • 📦 节点信息:系统版本、CPU、内存
  • 🖥️ VM 卡片:状态、CPU、内存、节点、IP、磁盘
  • ⚡ 操作按钮:Start / Stop / Restart / Migrate / Delete / Console
  • ➕ 创建 VM:表单式创建(名称、CPU、内存、镜像、Cloud-Init)
  • 🔄 自动刷新:每 10 秒

5. VM 管理命令速查

基础操作

bash
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml

# 列出所有 VM
kubectl get vm -A

# 列出所有 VMI (运行中的实例)
kubectl get vmi -A

# 查看 VM 详情
kubectl describe vm <name> -n <namespace>

# 查看 VMI 详情 (含 IP、节点等)
kubectl describe vmi <name> -n <namespace>

virtctl 操作

bash
# 启动/停止/重启
virtctl start <vm-name> -n <namespace>
virtctl stop <vm-name> -n <namespace>
virtctl restart <vm-name> -n <namespace>

# 暂停/恢复
virtctl pause vmi <vmi-name> -n <namespace>
virtctl unpause vmi <vmi-name> -n <namespace>

# 迁移
virtctl migrate <vm-name> -n <namespace>

# 控制台
virtctl console <vmi-name> -n <namespace>

# VNC (需要 virt-viewer)
virtctl vnc <vmi-name> -n <namespace>

# 端口转发
virtctl expose virtualmachine <vm-name> --port=22 --target-port=22 --type=NodePort -n <namespace>

创建 VM 示例

yaml
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: my-vm
  namespace: default
spec:
  running: true
  template:
    metadata:
      labels:
        kubevirt.io/vm: my-vm
    spec:
      domain:
        cpu:
          cores: 2
        memory:
          guest: 4Gi
        devices:
          disks:
            - name: rootdisk
              disk:
                bus: virtio
            - name: cloudinit
              disk:
                bus: virtio
          interfaces:
            - name: default
              masquerade: {}
      networks:
        - name: default
          pod: {}
      volumes:
        - name: rootdisk
          containerDisk:
            image: quay.io/containerdisks/ubuntu:22.04
        - name: cloudinit
          cloudInitNoCloud:
            userData: |
              #cloud-config
              password: xxx
              chpasswd: { expire: False }
              ssh_pwauth: true

使用 CDI DataVolume 导入磁盘

yaml
apiVersion: cdi.kubevirt.io/v1beta1
kind: DataVolume
metadata:
  name: harbor-disk
  namespace: default
spec:
  source:
    http:
      url: "http://<file-server>/harbor.qcow2"
  pvc:
    accessModes:
      - ReadWriteOnce
    resources:
      requests:
        storage: 50Gi
    storageClassName: local-path

6. VM 迁移计划

待迁移 VM

VM 名称磁盘文件大小用途
Harbor/var/lib/libvirt/images/harbor.qcow2~50GB容器镜像仓库
Jumpserver/var/lib/libvirt/images/jumpserver.qcow2~30GB堡垒机

迁移步骤

方案 A: HTTP 上传 (推荐)

  1. 启动临时 HTTP 服务器提供 qcow2 文件:
    bash
    cd /var/lib/libvirt/images/
    python3 -m http.server 8888
  2. 创建 DataVolume 指向该 HTTP 源
  3. 创建 VirtualMachine 引用该 PVC
  4. 验证数据完整性

方案 B: 直接复制到 local-path

  1. 创建 PVC (local-path storage class)
  2. 找到 PVC 对应的 PV 目录
  3. 使用 qemu-img convert 复制磁盘
  4. 创建 VirtualMachine 引用该 PVC

迁移后验证

bash
kubectl get vm -A
kubectl get vmi -A
virtctl console <vmi-name> -n default
kubectl get vmi <name> -o jsonpath='{.status.interfaces[0].ipAddress}'

7. 服务访问地址

服务地址说明
KubeVirt Web UIhttp://192.168.1.111:8080VM 管理界面
Open-WebUIhttp://192.168.1.111:30391AI 聊天界面
Ollama APIhttp://192.168.1.111:11434AI 模型 API
K3s APIhttps://192.168.1.111:6443K8s API Server

8. 附录:配置文件与路径

K3s 配置

文件用途
/etc/rancher/k3s/k3s.yamlK3s kubeconfig
/etc/rancher/k3s/registries.yaml容器镜像仓库配置
/var/lib/rancher/k3s/agent/etc/containerd/certs.d/*/hosts.tomlcontainerd 实际使用的镜像源
/var/lib/rancher/k3s/agent/etc/cni/net.d/10-flannel.conflistK3s flannel CNI 配置

CNI 网络

文件用途
/etc/cni/net.d/10-flannel.conflistMultus 使用的 flannel 配置 (从 K3s 复制)
/var/lib/rancher/k3s/agent/etc/cni/net.d/10-flannel.conflistK3s 原始 flannel 配置

存储

路径用途
/var/lib/libvirt/images/宿主机 libvirt VM 磁盘 (待迁移)
/var/lib/rancher/k3s/storage/local-path provisioner 存储目录

KubeVirt Web UI

文件用途
/opt/kubevirt-ui/server.pyPython API 后端
/opt/kubevirt-ui/index.html前端 SPA 页面
/etc/systemd/system/kubevirt-ui.servicesystemd 服务单元

变更记录

日期操作说明
2026-08-26部署 KubeVirt v1.9.09/9 Pod Running
2026-08-26部署 CDI v1.66.04/4 Pod Running
2026-08-26修复 registries.yaml添加 NJU 镜像源,重启 K3s 生效
2026-08-26修复 Multus CNI复制 flannel 配置到 /etc/cni/net.d/
2026-08-26修复 Ollama GPU 调度降低 gpumem 请求至 5000MB
2026-08-26安装 virtctl v1.9.0添加到 PATH
2026-08-26部署 KubeVirt Web UIsystemd 服务,端口 8080
2026-08-26创建测试 VMdemo-vm (已清理)