跳转至

KVM 宿主按配置创建 5 台 Rocky 9 主机 — 变更 SOP

工程位置:kvm_rocky9_deploy/ 本次配置:config/hosts-20260918.yaml(实现体:deployer.py、main.py、templates/ks.cfg.tmpl) 本文档为 C 类生产变更交付物;第 5 章为文档呈现,一切以实现体为准。


1. 背景

本次需要在一台既有 KVM 宿主(Dell PowerEdge R620)上创建 5 台 Rocky 9 主机,规格与 地址由使用方直接指定。宿主上已有另一批次创建的 6 台 k8s 主机与 1 台 OpenWrt 旁路由。

工程原先只服务于 k8s 一批主机(节点角色、etcd 数据盘、关闭 swap 等都写死在实现体与 模板里)。本次一并完成两件事:

  1. 实现体通用化:把与用途绑定的行为改为配置项,工程定位收敛为「按配置在 KVM 上 创建主机」——主机名、IP、MAC、CPU/内存、磁盘(数量、容量、格式、存储池、挂载点)、 登录方式(公钥或口令)全部由配置文件给出,不配即不生效。
  2. 新增本批次配置并创建 5 台主机。

通用化后新增的可选项(均有默认值,不配置即维持原行为):

配置项 作用 默认
vm_defaults.disable_swap 安装时是否关闭 swap true
vm_defaults.deflate_on_oom 是否启用内存气球 deflate-on-oom true
ssh.pubkey_file 注入的公钥;省略则不注入公钥 无
ssh.disable_password_auth 是否禁用口令登录 true
ssh.root_password 指定 root 口令;省略则随机生成并落盘 随机
nodes[].data_disks[] 数据盘列表,每块可配容量/格式/存储池/挂载点/卷名后缀 无
host_tuning.* 宿主内核参数与 KSM;整段省略则完全不碰宿主 不涉及

2. 目标

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

目标项 期望值
主机数量 5 台:slurm-master-01、slurm-master-02、slurm-work-01、slurm-work-02、slurm-work-03
操作系统 Rocky Linux 9.x
规格 master-01 4 vCPU / 4 GiB;master-02 2 vCPU / 2 GiB;work-01~03 各 8 vCPU / 16 GiB
系统盘 master 各 20 GiB、work 各 100 GiB(qcow2,落在 hdd-pool,稀疏分配)
数据盘 无
网络 桥接 br0,静态 IP 192.168.31.16–20,网关与 DNS 均为 192.168.31.2
登录 仅公钥登录(PasswordAuthentication no),注入宿主 rain 的 id_ed25519.pub
swap 关闭
开机自启 5 台均 autostart=yes
内存气球策略 5 台均启用 deflate-on-oom
既有环境 宿主内核参数与 KSM 服务零改动;既有 6 台 k8s 主机与 openwrt 零改动
幂等 连续第二次执行零变更、全跳过

3. 前置条件

权限与身份

  • 以 root 执行(需写 build/ 与 config/ 下的产物,并调用 virsh qemu:///system);宿主 rain 用户已配置免密 sudo。

依赖组件(均已存在)

组件 要求 校验命令
libvirt / QEMU libvirt 10.0、QEMU 8.2 virsh version
virt-install 4.1.0(--osinfo 必填) virt-install --version
libosinfo 含 rocky9 条目 osinfo-query os \| grep rocky9
ISO /data/kvm/iso/Rocky-9-latest-x86_64-dvd.iso ls -l /data/kvm/iso/
存储池 hdd-pool 处于 running virsh pool-list
SSH 公钥 /home/rain/.ssh/id_ed25519.pub ls -l /home/rain/.ssh/id_ed25519.pub

执行前检查项(本次已核查)

检查项 结论
目标 IP .16–.20 是否占用 逐台 ping 确认空闲
MAC 段 52:54:00:31:0b:01~05 是否冲突 比对全部既有域,无冲突
小米路由器 DHCP 池是否覆盖 .16–20 待人工确认,若覆盖需在路由器上排除该段
宿主内存余量 117 GiB total;本批次名义占用 54 GiB
宿主在跑作业 宿主上无调度类作业;既有主机保持运行

4. 影响范围

变更主机:KVM 宿主 dell-R620(唯一主机,全部操作在本机执行)。

工程侧改动(实现体通用化)

文件 动作
deployer.py 改写:节点角色/etcd 盘/关 swap 等改为配置驱动与可选,新增取值白名单校验
main.py 文案通用化,无逻辑变更
templates/ks.cfg.tmpl 占位符拆分为公钥/认证/数据盘/swap 四段,由配置决定是否生成
config/deploy.yaml、config/deploy.yaml.example 改写为通用格式(原 k8s 批次语义等价:卷名仍为 <主机名>-etcd.raw,挂载点仍为 /var/lib/etcd)

宿主侧改动:无。本批次配置未包含 host_tuning,实现体不读写 /etc/sysctl.d/99-kvm-host.conf 与 /etc/systemd/system/ksm.service。

虚机侧新增

对象 动作
磁盘卷 hdd-pool/slurm-*.qcow2 新增 5 个(20G×2、100G×3,qcow2 稀疏)
域定义 新增 5 个,并设置开机自启
主机内配置(kickstart 注入) 静态网络、主机名与 hosts、root 口令哈希、SSH 公钥、禁用口令认证、关闭 swap

是否停服:不停服。不重启宿主、不动 br0/netplan/物理网卡、不修改既有 6 台 k8s 主机与 openwrt 的任何定义或磁盘。

窗口期:无人值守安装按既有同规格实测(约 6–10 分钟/台)推算,并发度 2、共 5 台, 约 20–30 分钟。期间宿主 HDD 持续写入、CPU 与 IO 负载上升,属预期现象。

在跑业务:宿主上 openwrt 与 3 台 k8s 主机处于运行态(k8s-master-02/03 为 shut off), 本次变更不触碰它们。


5. 分步操作

对应实现文件:deployer.py(生命周期编排)、main.py(入口)、 templates/ks.cfg.tmpl(kickstart 模板);配置:config/hosts-20260918.yaml。 以下为与实现等价的操作序列,供阅读与手工复现;幂等、备份与错误处理由实现体保证。 命令均在工程根目录 kvm_rocky9_deploy/ 下执行。

5.1 预演(不改动任何状态)

sudo .venv/bin/python main.py --dry-run --config config/hosts-20260918.yaml   # 仅输出待变更清单

期望输出:配置解析完成:5 个节点、数据盘池=(未配置)、宿主调优=不涉及、 前置校验通过、10 项待变更(5 个系统盘 + 5 个域)。已实测通过。

5.2 宿主层:本批次不做任何改动

# 本配置未包含 host_tuning,实现体跳过宿主层;不生成、不修改、不删除
# /etc/sysctl.d/99-kvm-host.conf 与 /etc/systemd/system/ksm.service。
# 如需为其他批次改动宿主参数,在对应配置中显式声明 host_tuning 段。

5.3 创建系统卷(稀疏分配,不预占宿主空间)

virsh --connect qemu:///system vol-create-as hdd-pool slurm-master-01.qcow2 20G --format qcow2
virsh --connect qemu:///system vol-create-as hdd-pool slurm-master-02.qcow2 20G --format qcow2
virsh --connect qemu:///system vol-create-as hdd-pool slurm-work-01.qcow2 100G --format qcow2
virsh --connect qemu:///system vol-create-as hdd-pool slurm-work-02.qcow2 100G --format qcow2
virsh --connect qemu:///system vol-create-as hdd-pool slurm-work-03.qcow2 100G --format qcow2
# 本批次无数据盘(nodes[].data_disks 未配置),故不存在第二块盘

5.4 渲染 kickstart 并无人值守安装(每台一次,并发度 2)

# 每台渲染一份 build/<主机名>/ks.cfg,含:静态网络、主机名与 hosts 块、root 口令哈希、
# SSH 公钥注入、禁用口令认证、关闭 swap;本批次未配置数据盘,数据盘片段为空。
virt-install --connect qemu:///system \
  --name slurm-master-01 \
  --memory 4096 --vcpus 4 --cpu host-passthrough --machine pc \
  --osinfo name=rocky9 \
  --disk path=/data/kvm/img/slurm-master-01.qcow2,format=qcow2,bus=virtio,cache=none,io=native,discard=unmap \
  --network bridge=br0,mac=52:54:00:31:0b:01,model=virtio \
  --location /data/kvm/iso/Rocky-9-latest-x86_64-dvd.iso \
  --initrd-inject build/slurm-master-01/ks.cfg \
  --extra-args "inst.ks=file:/ks.cfg inst.text console=tty0 console=ttyS0,115200n8" \
  --graphics none --console pty,target_type=serial \
  --memballoon model=virtio --autostart --noautoconsole
# 注意:不要加 --boot hd,它会覆盖 virt-install 的 direct kernel boot
# 其余 4 台同构,仅替换 --name / --memory / --vcpus / --disk / --mac 取值

kickstart 以 poweroff 收尾(而非 reboot):此时域定义仍带 direct kernel boot 参数, 直接重启会再次进入安装器形成循环。

5.5 等待安装结束并固化域定义

# 判据:域转为 shut off(实现体按 15s 间隔轮询,上限 2400s)
virsh --connect qemu:///system domstate slurm-master-01        # 期望 shut off

virsh --connect qemu:///system dumpxml slurm-master-01 --inactive > build/slurm-master-01/domain.xml
# 移除 <kernel>/<initrd>/<cmdline>,改写为 <boot dev='hd'/>,使系统从硬盘引导
virsh --connect qemu:///system define build/slurm-master-01/domain.xml
virsh --connect qemu:///system start slurm-master-01

5.6 启用内存气球策略(deflate-on-oom)

# 说明:libvirt 10.0 的能力检测误判 QEMU 不支持该属性,直接写在 <memballoon> 内会被静默丢弃;
# 实测 QEMU 8.2 支持,故经 qemu:commandline 传 -global 绕过。
# 高危:以下操作会关闭并重启该主机,请在业务空闲窗口执行(新建主机此时无业务,风险可控)
virsh --connect qemu:///system destroy slurm-master-01
virsh --connect qemu:///system define build/slurm-master-01/domain.xml   # 已含 qemu:commandline
virsh --connect qemu:///system start slurm-master-01

5.7 设置开机自启

virsh --connect qemu:///system autostart slurm-master-01

6. 验证

# 1) 域状态:5 台均为 running,且既有 6 台 k8s 与 openwrt 状态不变
virsh --connect qemu:///system list --all

# 2) 引导方式已固化:不应出现 <kernel>/<initrd>
virsh --connect qemu:///system dumpxml slurm-master-01 --inactive | grep -cE "<kernel>|<initrd>"   # 期望 0

# 3) 内存气球策略:应输出 -global 与 virtio-balloon-pci.deflate-on-oom=on
virsh --connect qemu:///system dumpxml slurm-master-01 | grep -A4 qemu:commandline

# 4) 主机内部(对 5 台逐一执行,IP 取 .16–.20)
ssh -o BatchMode=yes root@192.168.31.16 '
  hostname; cat /etc/redhat-release; nproc; free -h | tail -n1;
  sshd -T | grep -i ^passwordauthentication;
  wc -l < /root/.ssh/authorized_keys;
  grep -c "[[:space:]]swap[[:space:]]" /etc/fstab'
# 期望:主机名与配置一致、Rocky Linux 9.x、nproc 与规格一致、swap 合计 0B、
#       passwordauthentication no、授权密钥 1 行、fstab 中 swap 行已注释

# 5) 磁盘容量
virsh --connect qemu:///system domblklist slurm-work-01            # 系统盘指向 100G 卷
qemu-img info /data/kvm/img/slurm-work-01.qcow2 | grep virtual

# 6) 既有环境未受影响的抽查
virsh --connect qemu:///system dumpxml k8s-master-01 | grep -c "52:54:00:31:0a:01"   # 期望 1
sysctl -n vm.swappiness                                                # 期望 10(本批次未改动)
systemctl is-enabled ksm.service                                       # 期望 enabled(本批次未改动)

# 7) 幂等复跑:第二次应零变更
sudo .venv/bin/python main.py --config config/hosts-20260918.yaml
# 期望输出:状态巡检:全部项已达标,无需变更 / 状态: skipped

7. 回滚

备份方式:实现体在改写既有文件前自动做带时间戳备份(<文件名>.bak.<YYYYmmdd-HHMMSS>)。 本批次宿主侧无改动,主机侧全部为新增对象。

回滚步骤

# 高危:销毁本配置中的全部 5 台主机与其磁盘数据(不可恢复)
sudo .venv/bin/python main.py --rollback --config config/hosts-20260918.yaml

由于本配置未包含 host_tuning,回滚只删主机与磁盘,不会触碰宿主内核参数与 KSM 服务, 也就不会影响 k8s 批次所依赖的宿主调优。等价的手工操作:

# 逐台执行(仅作用于本批次主机)
virsh --connect qemu:///system destroy slurm-master-01        # 高危:强制关闭
virsh --connect qemu:///system undefine slurm-master-01 --remove-all-storage   # 高危:连磁盘一并删除
# slurm-master-02 / slurm-work-01 / slurm-work-02 / slurm-work-03 同理

# 清理本次凭据文件(含明文口令)
rm -f config/credentials-slurm.yaml                           # 高危:删除凭据文件

回滚后验证

  • virsh list --all 中不再出现 5 台主机,且 k8s 6 台与 openwrt 状态与变更前一致
  • ls /data/kvm/img/slurm-*.qcow2 无输出
  • sysctl -n vm.swappiness 仍为 10、systemctl is-enabled ksm.service 仍为 enabled

工程侧改造的回退:改造前的 deployer.py、main.py、templates/ks.cfg.tmpl、 config/deploy.yaml* 已留存快照于 _backup_before_refactor_20260918/,需要时可直接覆盖还原 (还原后本批次的通用格式配置需一并回退)。确认新版本稳定后该目录可删除。


8. 风险说明

风险点 影响 缓解措施
宿主内存压力 本批次名义 54 GiB;若 k8s-master-02/03 同时开机(+8 GiB),可用余量仅约 9 GiB 已启用 deflate-on-oom;如不需常驻,可对部分主机执行 virsh autostart --disable,或将配置中 vm_defaults.autostart 改为 false 后重跑
静态 IP 与路由器 DHCP 池冲突 间歇性断网,且难归因 执行前确认 DHCP 池范围,或在路由器上排除 192.168.31.16–20(本项尚未人工确认)
--boot hd 覆盖 direct boot 域无 <kernel>,主机从空盘引导后立即关机,且无日志 不传 --boot;安装后由实现体移除 direct boot 参数
kickstart 以 reboot 收尾会循环安装 域定义仍带 direct boot,重启再次进安装器 模板固定 poweroff 收尾,由实现体固化定义后再启动
libvirt 静默丢弃 deflate-on-oom virsh define 返回成功但配置未生效 经 qemu:commandline 传 -global;验证时直接查域 XML
并发安装争抢 HDD IO 安装变慢 并发度限制为 2;如需更快可提高,但会加剧争抢
关闭 swap 的影响 内存超用时无换页兜底,进程可能被 OOM 终止 由 vm_defaults.disable_swap 控制;若使用方需要 swap,改为 false 重建即可
配置取值进入 guest 内脚本 错误的挂载点/主机名可能破坏 kickstart 或造成脚本注入 实现体对主机名、IP、MAC、卷名后缀、挂载点做白名单校验,并在批次内查重,不通过则前置校验直接失败
root 口令 明文落盘 未在配置中指定时由实现体随机生成 24 位口令存于 config/credentials-slurm.yaml(已 gitignore),供控制台兜底登录
历史文档漂移 docs/SOP.md 为 k8s 批次的旧文档,其第 5 章仍按改造前的字段描述(如 etcd 盘) 该文档第 5 章为「文档呈现」,以实现体为准;如需对外交付应同步更新

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