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. 目标¶
变更完成后应达到以下可验证状态:
kvm-ok输出KVM acceleration can be used;libvirtd服务enabled,且libvirtd.socket处于监听(Ubuntu 24.04 为 socket 激活:空闲时libvirtd.service退出显示inactive (dead)属正常);virsh version/virsh nodeinfo正常返回;- 定义并启动两个存储池:
hdd-pool(/data/kvm/img,默认位置)与ssd-pool(/kvm/img),均开机自启; - AppArmor 已放行
/kvm/**与/data/**; - 目标用户
rain已在libvirt、kvm组中; - 已安装
virt-manager,并启用kvm_intel nested=1; - 物理网络配置与变更前完全一致(
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同步,请勿在站点侧修改)