跳转至

SOP:KVM 宿主基线部署(dell-R620 / Ubuntu 24.04)

变更类型:C 类(生产变更) 目标主机:dell-R620(单机,无冗余) 实现体:本工程 Python 部署程序(入口 main.py,业务类 deployer.py) 边界声明:仅部署 KVM 宿主基线,不修改任何物理网络配置


1. 背景

dell-R620 已重装为 Ubuntu 24.04.3 LTS,需要在其上建立 KVM 虚拟化能力,作为后续虚拟机的运行底座。

变更前实测现状(只读巡检):

项 实测
系统 Ubuntu 24.04.3 LTS(桌面版),内核 7.0.0-31-generic,UEFI 引导
CPU 2× Xeon E5-2650 v0,16C/32T,VT-x 已启用,kvm_intel 已加载
内存 117 GiB
磁盘 sda 249.5G(SSD)= / 223.8G;sdb 1999.3G(2×1T RAID0)= /data 1.8T
网络 eno1=.249(默认路由)、eno2=.250(SSH 入口)、eno3=.251;渲染器 NetworkManager;无网桥
KVM 未安装(libvirtd not-found、无 virsh/virt-install);/dev/kvm 存在

为什么本 SOP 不含网络变更:规划中的 br0 用于承载 192.168.0.0/24(网关为 OpenWrt 的 .1)。当前 OpenWrt 路由 VM 尚未恢复,该网段不存在;此刻迁移 IP 会立即丢失默认路由导致失联,且 iDRAC(192.168.0.120)当前不可达、无带外兜底。故网桥留待「恢复 OpenWrt」阶段统一规划。


2. 目标

变更完成后应达到以下可验证状态:

  1. kvm-ok 输出 KVM acceleration can be used;
  2. libvirtd 服务 enabled,且 libvirtd.socket 处于监听(Ubuntu 24.04 为 socket 激活:空闲时 libvirtd.service 退出显示 inactive (dead) 属正常);
  3. virsh version / virsh nodeinfo 正常返回;
  4. 定义并启动两个存储池:hdd-pool(/data/kvm/img,默认位置)与 ssd-pool(/kvm/img),均开机自启;
  5. AppArmor 已放行 /kvm/** 与 /data/**;
  6. 目标用户 rain 已在 libvirt、kvm 组中;
  7. 已安装 virt-manager,并启用 kvm_intel nested=1;
  8. 物理网络配置与变更前完全一致(eno1/eno2/eno3 地址、默认路由、SSH 连通性均不变)。

3. 前置条件

项 要求
权限 具备 sudo;脚本以 root 运行(不静默提权,检测到非 root 直接终止)
系统 Ubuntu(脚本校验 /etc/os-release 中 ID=ubuntu)
硬件 BIOS/UEFI 已启用 Intel VT-x(/dev/kvm 存在)
Python 系统 Python ≥ 3.9(实测 3.12.3);使用工程内 .venv
共享库 /home/rain/py_public_modules 由 venv 的 .pth 引入(已挂载)
依赖 paramiko>=3.0、PyYAML>=6.0(记录于 requirements.txt)
配置文件 config/deploy.yaml(由 deploy.yaml.example 复制修改)

环境准备(首次):

cd kvm_host_deploy
python3 -m venv .venv
.venv/bin/python -c "import sysconfig, pathlib; p = pathlib.Path(sysconfig.get_paths()['purelib']) / 'py_public_modules.pth'; p.write_text('/home/rain/py_public_modules', encoding='utf-8')"
.venv/bin/python -m pip install -r requirements.txt
.venv/bin/python -c "import sys, importlib.util as u; t='/home/rain/py_public_modules'; print(t in sys.path, u.find_spec('config_module').origin)"

执行前检查项:[ -e /dev/kvm ]、df -h / /data(SSD 剩余 ≥ 20G)、who(确认当前 SSH 来源)。


4. 影响范围

维度 说明
主机 仅 dell-R620 一台(无备机、无冗余,出问题无其他节点顶替)
涉及组件 apt 软件包集合、libvirtd 服务、libvirt 存储池、AppArmor 策略、kvm_intel 模块参数
是否停服 否。不重启宿主、不重启 Docker、不重启网络
在跑业务 Docker 29.1.3、远程 agent;均不受影响
网络影响 无。三块网卡与默认路由保持不变,SSH 不中断
磁盘影响 新建 /kvm/{img,iso}、/data/kvm/{img,iso,backup};不格式化、不删数据
敏感变更 修改 AppArmor 策略文件、写入 kvm_intel 模块参数(变更前自动带时间戳备份)
窗口期 无需停机窗口;执行耗时约 1–2 分钟(不含 apt 下载)

5. 分步操作

以下命令序列与实现体 deployer.py 中 KvmHostDeployer.execute() 的七个子步骤一一对应,供人工复核与手工复现;以实现体为准。脚本执行时会先判状态,已达标即跳过。

# ---------- 1. 软件包(实现:_ensure_packages / _apt_install)----------
apt-get update -qq                                  # 刷新索引(仅在存在缺失包时执行)
apt-get -y install \
    qemu-system-x86 qemu-utils \
    libvirt-daemon-system libvirt-clients \
    virtinst libosinfo-bin \
    ovmf cpu-checker bridge-utils virt-manager
# 注:qemu-kvm 在 Ubuntu 24.04 是虚拟包(由 qemu-system-x86 提供),无须显式安装

# ---------- 2. libvirt 服务(实现:_ensure_service)----------
systemctl enable --now libvirtd                     # 开机自启
systemctl is-active libvirtd.socket                 # 健康判据看 socket:
                                                    # libvirtd.service 空闲时会自行退出,属正常

# ---------- 3. 用户组(实现:_ensure_user_groups)----------
usermod -aG libvirt,kvm rain                        # 需重新登录(或 newgrp libvirt)后生效

# ---------- 4. 存储目录(实现:_ensure_directories)----------
mkdir -p /data/kvm/img                              # HDD:默认镜像位置
mkdir -p /kvm/img                                   # SSD:备用池(IO 敏感的 VM)
mkdir -p /kvm/iso /data/kvm/iso /data/kvm/backup    # ISO 与备份

# ---------- 5. AppArmor 放行(实现:_ensure_apparmor)----------
# 【高危】改前先带时间戳备份,避免策略丢失
cp -a /etc/apparmor.d/local/abstractions/libvirt-qemu \
      /etc/apparmor.d/local/abstractions/libvirt-qemu.bak.$(date +%Y%m%d-%H%M%S)
echo '/kvm/** rwk,'  >> /etc/apparmor.d/local/abstractions/libvirt-qemu
echo '/data/** rwk,' >> /etc/apparmor.d/local/abstractions/libvirt-qemu
systemctl reload apparmor                           # 放行后必须重载,否则 VM 仍起不来

# ---------- 6. 存储池(实现:_ensure_pools / _ensure_single_pool)----------
virsh --connect qemu:///system pool-define-as hdd-pool dir --target /data/kvm/img
virsh --connect qemu:///system pool-build     hdd-pool
virsh --connect qemu:///system pool-start     hdd-pool
virsh --connect qemu:///system pool-autostart hdd-pool
virsh --connect qemu:///system pool-define-as ssd-pool dir --target /kvm/img
virsh --connect qemu:///system pool-build     ssd-pool
virsh --connect qemu:///system pool-start     ssd-pool
virsh --connect qemu:///system pool-autostart ssd-pool

# ---------- 7. 嵌套虚拟化(实现:_ensure_nested)----------
# 【高危】改前备份已有配置
cp -a /etc/modprobe.d/kvm-nested.conf \
      /etc/modprobe.d/kvm-nested.conf.bak.$(date +%Y%m%d-%H%M%S) 2>/dev/null
echo 'options kvm_intel nested=1' > /etc/modprobe.d/kvm-nested.conf
modprobe -r kvm_intel && modprobe kvm_intel         # 模块被占用时退化为「重启后生效」

实际执行方式(幂等,重复执行第二次全部跳过):

sudo .venv/bin/python main.py --dry-run --config config/deploy.yaml   # 预演
sudo .venv/bin/python main.py --config config/deploy.yaml             # 执行

6. 验证

# 1) 硬件加速
kvm-ok
# 预期:INFO: /dev/kvm exists / KVM acceleration can be used

# 2) 服务(socket 激活:以 socket 是否监听为准)
systemctl is-enabled libvirtd && systemctl is-active libvirtd.socket
# 预期:enabled / active

# 3) 虚拟化层可用
virsh --connect qemu:///system version | head -4
virsh --connect qemu:///system nodeinfo | head -6
virsh --connect qemu:///system list --all            # 预期:空列表(尚未创建 VM)

# 4) 存储池
virsh --connect qemu:///system pool-list --all --details
# 预期:hdd-pool / ssd-pool 均为 running,Autostart=yes

# 5) AppArmor 放行
grep -n "rwk," /etc/apparmor.d/local/abstractions/libvirt-qemu
# 预期:/kvm/** rwk, 与 /data/** rwk, 各一行

# 6) 用户组
id -nG rain | tr ' ' '\n' | grep -E '^(libvirt|kvm)$'
# 预期:两行(libvirt、kvm)

# 7) 嵌套虚拟化
cat /sys/module/kvm_intel/parameters/nested           # 预期:Y

# 8) 网络回归项(红线:必须与变更前一致)
ip -br addr show eno1 && ip -br addr show eno2 && ip -br addr show eno3
ip route | grep default                               # 预期:default via 192.168.31.1 dev eno1

幂等验证(必做):连续执行两次,第二次应判定「所有变更项均已达标」,不产生任何变更。

sudo .venv/bin/python main.py --config config/deploy.yaml
sudo .venv/bin/python main.py --config config/deploy.yaml   # 预期:状态巡检全达标、跳过备份与执行

7. 回滚

7.1 备份方式

对象 备份方式
/etc/apparmor.d/local/abstractions/libvirt-qemu backup() 阶段调用基类 auto_backup(),生成 .bak.<时间戳>
/etc/modprobe.d/kvm-nested.conf 同上
执行日志 logs/kvm-host-deploy.log(按日切割,保留 30 天)

7.2 回滚触发判据(量化,任一命中即回滚)

  • 程序返回非 0,或结果状态为 failed;
  • systemctl is-active libvirtd.socket 非 active;
  • virsh --connect qemu:///system version 报连接失败;
  • 校验阶段出现任一 ❌ 校验未通过;
  • 网络回归项不符:eno1/eno2/eno3 地址或默认路由变化、SSH 中断。

7.3 回滚步骤

# ① 恢复配置文件(自动取最近一次时间戳备份)
sudo .venv/bin/python main.py --rollback --config config/deploy.yaml

# ② 撤销嵌套虚拟化参数
sudo rm -f /etc/modprobe.d/kvm-nested.conf
sudo modprobe -r kvm_intel && sudo modprobe kvm_intel    # 或重启生效

# ③ 销毁存储池(不影响 /data 已有数据)
virsh --connect qemu:///system pool-destroy ssd-pool; virsh --connect qemu:///system pool-undefine ssd-pool
virsh --connect qemu:///system pool-destroy hdd-pool; virsh --connect qemu:///system pool-undefine hdd-pool

# ④ 停用服务
sudo systemctl disable --now libvirtd

# ⑤ 卸载软件包(可选;purge 会删 /etc/libvirt 配置,执行前确认无 VM 定义需保留)
sudo apt-get -y purge qemu-system-x86 qemu-utils libvirt-daemon-system libvirt-clients \
    virtinst libosinfo-bin ovmf virt-manager

# ⑥ 目录清理(【高危】仅在确认目录内无数据时执行)
sudo rmdir /kvm/img /kvm/iso /kvm 2>/dev/null || true
# /data/kvm 内含用户数据,默认保留不删

7.4 回滚后验证

command -v virsh || echo "virsh 已移除"
systemctl is-active libvirtd.socket || echo "libvirt socket 已停止"
grep -c "rwk," /etc/apparmor.d/local/abstractions/libvirt-qemu 2>/dev/null || echo "AppArmor 放行已撤销"
ip -br addr show eno1        # 预期仍为 192.168.31.249

8. 风险说明

风险点 说明 缓解措施
网络失联(最高) 本工程不碰网络,理论无风险;但后续手工建 br0 若误动 eno1/eno2,将切断 SSH,且 iDRAC 当前不可达(不同网段),只能靠物理控制台 网桥变更单独开窗口,先在物理控制台待命;本 SOP 已明确排除网络变更
AppArmor 拦截 未放行自定义镜像路径会导致 VM 启动失败(apparmor="DENIED"),是 Ubuntu 上 KVM 最常见故障 自动放行 /kvm/**、/data/** 并重载;排障用 journalctl -n 30 \| grep -i "apparmor.*denied"
Docker 与 libvirt 转发冲突 Docker 会改写 iptables FORWARD 链(默认 DROP),可能影响 virbr0/网桥转发的 VM 出网 本工程不动网络;若后续 NAT 出网异常,检查 iptables -L FORWARD -n -v 与 iptables -t nat -L
virbr0 默认网络 libvirt 自带 NAT 网络 192.168.122.0/24,与 docker0(172.17.0.0/16)不冲突 本工程只读取、不启停;需要纯桥接时再 virsh net-destroy default && virsh net-autostart --disable default
内核模块热重载 有 VM/进程占用时 modprobe -r kvm_intel 会失败 程序已容错:配置落盘并提示「重启后生效」,不中断执行
UEFI 引导差异 本机为 UEFI。QEMU 默认 SeaBIOS 仍可引导 legacy 镜像(如 OpenWrt),启用 UEFI 需显式指定 OVMF 已安装 ovmf 备用;创建 legacy 镜像 VM 时不要指定 <loader>
RAID0 无冗余 /data 位于 2×1T RAID0,任一盘故障即全损 重要 VM 数据需另做异地备份(/data/kvm/backup 仅为本机目录,不等于备份)
桌面版开销 系统为桌面版(GNOME),内存/CPU 有额外占用 117 GiB 内存充裕;如需极致性能可后续切到无桌面运行级别

9. 附:创建 VM 时的性能基线建议

维度 建议
CPU 模型 <cpu mode='host-passthrough'/>
vCPU 拓扑 按物理拓扑给 sockets/cores/threads,避免「1 socket × N core」默认写法
磁盘总线 virtio-blk 或 virtio-scsi,cache='none'、io='native'
网络 virtio-net + vhost-net,多队列数 = vCPU 数
内存 内存密集型(EDA/仿真)可后续启用 2M 静态大页:vm.nr_hugepages
时钟 guest 内 current_clocksource 应为 kvm-clock
guest 工具 guest 内安装 qemu-guest-agent,宿主可正常关机、读取 IP
存储位置 默认 hdd-pool(/data/kvm/img);对 IO 敏感的 VM 用 ssd-pool(/kvm/img)

来源:/home/rain/Documents/kvm/kvm_deploy/docs/SOP.md | 最后更新:2026-09-15 00:00(由 build/sync.py 同步,请勿在站点侧修改)