Skip to content

Harvester v1.8.2 三节点 ISO 无人值守部署 · 一键部署包

本目录是可直接落地的部署资料包:一键入口 + 19 个已实测脚本 + 真实装机配置 + libvirt 域/网络定义。 原理与逐字段说明见 ../01-实施手册-ISO无人值守装机.md, 踩坑与根因见 ../02-故障排查与修复记录.md, 认证专题见 ../03-凭据与首登认证.md

实测结果:3 节点全部 Ready control-plane,etcd,etcd 成员 3/3,异常 Pod 0, Dashboard admin 可登录;总编排耗时 42 分钟


1. 资料包内容

deploy/
├── README.md                     # ← 本文:一键部署文档
├── run-all.sh                    # ★ 一键入口(前置检查 + 按序调用下列脚本)
├── scripts/                      # 19 个已实测脚本(可直接运行)
│   ├── 00-download.sh            #   下载 vmlinuz/initrd/rootfs/ISO(9.5GB,断点续传)
│   ├── 10-prepare.sh             #   磁盘/NVRAM/HTTP 符号链接/DHCP 静态保留
│   ├── 20-http-server.sh         #   启动 HTTP 引导服务(幂等)
│   ├── 30-console-capture.sh     #   串口录制(pty + script,日志轮转 .prev)
│   ├── 40-define-vm.sh           #   生成三态域定义 probe/install/disk
│   ├── 50-gen-configs.sh         #   生成 config-nodeNN.yaml + token + credentials
│   ├── 60-deploy.sh              #   单节点编排(装机→切盘→autostart→等 Ready)
│   ├── 61-autostart-after-iso.sh #   等 ISO 下完自动接力 node01
│   ├── 65-deploy-all.sh          #   ★ 总编排(node02/03 + 改密 + 验证 + 自愈)
│   ├── 70-verify.sh              #   集群验证(9 个检查段)
│   ├── 75-set-admin-password.sh  #   ★ Dashboard 首登改密(幂等)
│   ├── 80-smoke-vm.sh            #   端到端测试 VM(当前受已知问题阻塞,见 §9)
│   ├── 90-progress.sh            #   30s 粒度进度记录
│   ├── 95-rescue-image-preload.sh        # 自愈 L2:镜像预加载卡死救援(宿主侧)
│   ├── 95-rescue-image-preload-guest.sh  # 自愈 L2:救援体(guest 内执行)
│   ├── 96-install-retry.sh               # 自愈 L3:安装器卡死自动重启重试
│   ├── 97-installer-netfix.sh            # 自愈 L1:抢注入 nm-online 包装
│   ├── 98-nm-online-wrapper.sh           # 自愈 L1:被注入的包装体
│   └── 99-rancher-internal-net.sh        # 可选:接入内网 Rancher(A~F 六步,见 ../05)
└── configs/                      # 真实配置样本(可直接比对/复用)
    ├── config-node01.yaml        #   create 模式(含 vip / vip_mode;DNS 已收敛为单一宿主 dnsmasq)
    ├── config-node02.yaml        #   join 模式(含 server_url,无 vip)
    ├── config-node03.yaml        #   join 模式
    ├── harvester-net.xml         #   libvirt 网络定义(virbr10 / NAT / DHCP 池)
    └── vm/
        ├── harvester-01-install.xml   # netboot 装机态域定义(含完整 cmdline)
        └── harvester-01-disk.xml      # 硬盘启动态域定义

2. ★ 一键部署(三条命令)

bash
# ① 落地资料包到项目目录(若从零开始)
mkdir -p /mnt/xfs/harvester/scripts
cp -a deploy/scripts/*.sh deploy/run-all.sh /mnt/xfs/harvester/scripts/

# ② 前置检查(不改动任何状态,强烈建议先跑)
bash /mnt/xfs/harvester/scripts/run-all.sh --preflight

# ③ 一键部署:下载介质 → 建盘 → HTTP → 配置 → node01 → node02/03 → 改密 → 验证
setsid bash /mnt/xfs/harvester/scripts/run-all.sh </dev/null > /tmp/run-all.log 2>&1 &
tail -f /tmp/run-all.log

介质已下载过时用 --skip-download;中断后续跑用 --from <阶段>

run-all.sh 不含任何新的部署逻辑:它只做前置检查,然后按序调用 scripts/ 里已实测的分步脚本,行为与手工逐条执行完全一致。 因此排障时随时可以退回手工分步(见 §8)。

2.1 run-all.sh 参数

参数作用
--preflight只做前置检查后退出(不改状态)
--skip-download跳过 9.5GB 介质下载
--from <阶段>从指定阶段续跑
--help打印用法

阶段顺序:preflight → download → prepare → http → configs → node01 → all → verify

环境变量默认说明
BASE/mnt/xfs/harvester项目根目录
VIP192.168.150.200管理 VIP
HTTP_IP / HTTP_PORT192.168.150.1 / 8080引导服务监听
OS_DISK_DIR$HOME/harvester-disks★ os 盘实体目录,必须在 NVMe

退出码:0 成功 | 1 前置检查/参数错误 | 2 某阶段失败。

2.2 前置检查都查什么(8 项,均来自实测踩坑)

#检查项不通过的后果对应案例
1BASE 与 9 个必需脚本存在流程中断
2依赖命令 virsh/qemu-img/python3/curl/jq/setsid/script/awksshpass 仅告警)改密脚本要 jq;救援脚本要 sshpass03 §5.2
3/dev/kvm 存在且可读写;CPU 有 vmx/svmguest 内 KubeVirt 跑不了虚机案例 6
4OS_DISK_DIR 是否机械盘(读 /sys/block/<disk>/queue/rotational预加载 >30min → 永久卡死案例 7
5BASE 可用空间 ≥40G介质 + 磁盘增长放不下
6HTTP 端口状态(已监听则复用)
7VIP 归属:/ping → pong 判定为"已有集群",否则有应答即告警VIP 冲突会导致 kube-vip 抢地址
8★ 是否已有编排器在跑(pgrep重复实例互相 destroy/define/start01 §7 阶段 5

实测输出(本环境,集群已就绪):

=== 阶段 preflight:前置检查 ===
  OK  os 盘实体目录 /home/<user>/harvester-disks(/dev/nvme0n1p2 → nvme0n1,rotational=0 非机械盘)
  OK  192.168.150.1:8080 已在监听(20-http-server.sh 会直接复用)
  OK  VIP 192.168.150.200 上已有 Harvester 集群在跑(/ping → pong):本次为**重跑/续跑**
preflight 通过

第 4 项已做双向验证:把 OS_DISK_DIR=/mnt/xfs(真实机械盘)传入时正确告警 rotational=1,说明判定是实读 sysfs 而非硬编码。


3. 宿主机要求与容量规划

最低本环境实测说明
CPU支持 VT-x/AMD-V,≥24 核可用8 vCPU × 3 = 24 vCPUguest 内要跑 KubeVirt,需嵌套虚拟化
内存≥96 GiB32 GiB × 3 = 96 GiBHarvester 单节点门槛较高
NVMe/SSD≥250 GB 可用/home/<user>/harvester-disks(283GB 可用)os 盘实体必须放这里,否则踩案例 7
大容量盘≥1.2 TB/mnt/xfs(data 盘 3×400GiB qcow2)Longhorn 数据盘;qcow2 精简置备,实际占用随写入增长
系统Linux + libvirt ≥8.0 + qemu-kvmlibvirt 8.0注意 8.0 不支持 discard='unpin'(案例 2)
依赖包virsh qemu-img python3 curl jq sshpass util-linux(script) procps齐备jq 供改密脚本,sshpass 供装机期救援
出网能访问 releases.rancher.com下载 9.5GB 介质;生产建议先内网镜像化

磁盘布局(★ 这是本次最重要的一条经验)

NVMe(宿主根文件系统)  →  3 × os 盘实体 250GiB qcow2   →  guest /dev/vda
/mnt/xfs(机械盘)      →  3 × data 盘实体 400GiB qcow2 →  guest /dev/vdb(Longhorn)
/mnt/xfs/harvester/disks/harvester-NN-os.qcow2  是**符号链接**指向 NVMe 实体

os 盘放机械盘会让装机期"8GB ISO 下载 + 200 个镜像导入"读写同轴争抢, 实测预加载 ~34 分钟 > rke2 的 30 分钟 static-pods 死线 → 永久卡死(案例 7)。


4. 部署过程会发生什么(实测时间线)

时刻阶段你会看到耗时
T+0download4 个介质文件下载进度~44 分钟(9.5GB)
T+44mprepare建 6 个 qcow2、3 个 NVRAM、3 条 DHCP 保留秒级
T+44mhttp192.168.150.1:8080 开始监听秒级
T+44mconfigs生成 3 份 config.yaml + token.txt + credentials.txt秒级
T+45mnode01 装机串口日志滚动:dracut → live 环境 → harv-install → elemental → 预加载镜像15~20 分钟
node01 切盘启动powered off after install → 切 disk 定义 → autostart → 开机~1 分钟
node01 就绪ssh up (~50s)VIP respondingReady~2 分钟
node02 装机+join同上,随后被自动提升为 control-plane,etcd~19 分钟(实测装机 1006s)
node03 装机+join同上~22 分钟
改密=== set dashboard admin password =xxx → mustChangePassword: xxx秒级
验证70-verify.sh 9 个检查段 → === ALL DONE ===~1 分钟
T+87m完成三节点 HA 集群可用总编排 42 分钟(不含下载)

4.1 观察点(按重要性排序)

bash
tail -f /mnt/xfs/harvester/logs/deploy-all.log      # ★ 总编排:阶段推进与自愈动作
tail -f /mnt/xfs/harvester/logs/deploy.log          # 单节点编排细节
cat     /mnt/xfs/harvester/logs/deploy.status       # 当前阶段(一行)
tail -f /mnt/xfs/harvester/logs/harvester-02-console.log   # ★ 装机串口实况
tail -f /mnt/xfs/harvester/logs/progress.log        # 30s 汇总(VM 状态/磁盘写入量)

4.2 判卡阈值(超过就该介入)

现象阈值动作
单节点装机未 powered off>25 分钟看串口日志定位阶段
同上>30 分钟基本可断定踩中预加载死线 → 案例 7
串口刷 connection refused持续 >2 分钟L2 救援应已触发;未触发则手工 95 … run
串口停在错误界面且静默>60sL3 应自动 virsh reboot;查 logs/retry-NN.count
节点 NotReady>10 分钟kubectl describe node + 节点 journalctl

5. 验收清单

5.1 集群层(bash scripts/70-verify.sh 可自动覆盖)

  • [ ] virsh list --all:3 个域 running
  • [ ] virsh dominfo harvester-0N | grep Autostart:3 个均 enable
  • [ ] kubectl get nodes -o wide:3 行,STATUSReady(或提升期 Ready,SchedulingDisabled
  • [ ] ROLES:3 个均 control-plane,etcd(自动提升完成)
  • [ ] kube-systemetcd-harvester-01/02/033 个 Running(quorum 成立)
  • [ ] kube-systemkube-vip:3 个(每节点 1 个)
  • [ ] 异常 Pod(非 Running/Completed/Succeeded):0
  • [ ] longhorn-systemnodes.longhorn.io:3 节点,default-disk schedulable=true
  • [ ] kubectl get sc:含默认 harvester-longhorn
  • [ ] 三节点 SSH 免密可登录,uname -r 一致(6.12.0-160000.36-default

5.2 接入层

  • [ ] curl -sk https://<VIP>/ping200 且响应体 pong
  • [ ] curl -skL https://<VIP>/dashboard/200 且能取到 <title>
  • [ ] bash scripts/75-set-admin-password.shrc=0(幂等短路即代表凭据可用)
  • [ ] 浏览器打开 https://<VIP>/,用 \1xxx\2 登录成功,不弹强制改密页

5.3 交付物

  • [ ] configs/credentials.txt 存在且权限 600,三类凭据标签正确(见 ../03 §6)
  • [ ] configs/token.txt 存在(三节点一致的 RKE2 join token)
  • [ ] logs/ 下保留完整串口日志(含 .prev 轮转),可供复盘
  • [ ] logs/deploy-all.log 末尾出现 === ALL DONE ===

6. 失败处置

6.1 先别急着重跑:三层自愈会自己处理

触发你会在日志里看到
L1 网络竞态开机 +47~55s 抢注入97-installer-netfix.sh 的输出
L2 预加载卡死每 ~30s 探测harvester-0N: preload rescue triggered
L3 安装器卡死每 ~30s 探测harvester-0N: installer restarted (自动重试)

L3 限流:每节点 ≤3 次、间隔 ≥120s,重启后等待预算顺延(不会因为重试而更容易超时)。

6.2 需要人工介入的情形

情形处置
某节点三次重试后仍失败logs/harvester-NN-console.log(及 .prev)定位;修好后 bash scripts/60-deploy.sh nodeNN 单独重装
总编排报 部署结束, 但以下节点失败: NN逐台修,然后重跑 bash scripts/65-deploy-all.sh(幂等,已就绪节点会被快速跳过)
改密失败(WARN: 设定 admin 密码失败xxxbash scripts/75-set-admin-password.sh
编排器被误杀pgrep -af '60-deplo[y]|65-deplo[y]' 确认没有残留实例,再重启(重复实例会互相打断)
域卡在 netboot 装机态virsh dumpxml harvester-NN | grep -c '<kernel>' 为 1 即仍在装机;ensure_booted_from_disk 会自动切盘
需要彻底重来../04-运维手册-巡检重置与网络打通.md §4.1(会删数据

6.3 重跑安全性(幂等性一览)

脚本重复执行说明
20-http-server.sh✅ 安全已监听则直接退出
50-gen-configs.sh✅ 安全token.txt 已存在则复用(三节点必须一致)
65-deploy-all.sh✅ 安全已就绪节点走 running from disk 快速通道;改密短路
70-verify.sh✅ 安全纯只读
75-set-admin-password.sh✅ 安全先用目标密码试登录,成功即短路
10-prepare.sh⚠️ 谨慎会创建磁盘;已有 qcow2 时注意别覆盖数据
60-deploy.sh nodeNN⚠️ 会重装重新走 netboot 装机 = 抹掉该节点,务必确认
00-download.sh✅ 安全断点续传

7. 参数定制指南(换环境要改哪些地方)

7.1 支持环境变量覆盖的(优先用这些)

变量生效脚本默认值
BASErun-all.sh/mnt/xfs/harvester
VIPrun-all.sh75-set-admin-password.sh192.168.150.200
HTTP_IP / HTTP_PORTrun-all.sh192.168.150.1 / 8080
OS_DISK_DIRrun-all.sh(仅用于前置检查判定)$HOME/harvester-disks
NVME_DISK_DIR10-prepare.sh(★ 真正决定 os 盘实体位置)/home/<user>/harvester-disks
BOOT_PW75-set-admin-password.shadmin
IMG_URL80-smoke-vm.shUbuntu noble cloud image

7.2 需要改脚本内变量的(硬编码点,逐项列出)

要改什么文件 : 行/变量
Harvester 版本00-download.sh:610-prepare.sh:640-define-vm.sh:650-gen-configs.sh:6VER=v1.8.2;另 61-autostart-after-iso.shEXPECT=(ISO 字节数)
项目根目录所有脚本首部的 BASE=/mnt/xfs/harvesterrun-all.sh 除外,它支持环境变量)
磁盘大小10-prepare.sh:7 OS_DISK_SIZE=250G:8 DATA_DISK_SIZE=400G
vCPU / 内存40-define-vm.sh:8 RAM_KIB=33554432:9 VCPUS=8
节点 IP10-prepare.sh:20 IP[]60-deploy.sh:16 node_ip()65-deploy-all.sh:15 node_ip()70-verify.sh 的 IP 列表、80-smoke-vm.sh:6 NODE95/96/97 各自的 node_ip
MAC10-prepare.sh:19 MAC[]40-define-vm.sh:12 mac="52:54:00:15:01:${n}"50-gen-configs.shhwAddr 生成
VIP50-gen-configs.sh:960-deploy.sh:965-deploy-all.sh:1370-verify.sh:575-set-admin-password.sh:25
HTTP 引导服务20-http-server.sh:5 BIND / :6 PORT50-gen-configs.sh:7-840-define-vm.sh:7 HTTP
guest 网卡名50-gen-configs.sh:10 IFNAME=enp1s0 ← ★ 换机型/PCI 布局必须重新探测引导(案例 1)
节点 DNS50-gen-configs.shdns_nameservers ← ★ 只留宿主 dnsmasq,勿并列公网 DNS(CoreDNS policy=random 会间歇解析到公网,案例 24)
密码xxxPASSWORD(OS/SSH = xxx)与 DASHBOARD_PW(dashboard = xxx);75-set-admin-password.shNEW_PW 默认取后者。★ 两者故意不同值,避免把 SSH 密码当 dashboard 密码(xxx 案例 28)
SSH 公钥50-gen-configs.sh:12 SSHKEY="$(cat $HOME/.ssh/id_rsa.pub)"
RKE2 join tokenconfigs/token.txt(首次由 openssl rand -hex 16 生成;重装时必须保持一致,否则 join 失败)

7.3 批量换网段/根目录(一键 sed)

bash
cd /mnt/xfs/harvester
# 换项目根目录 + 换整个 /24 网段(所有 IP 共用前缀,故可整体替换)
find scripts -name '*.sh' -exec sed -i \
  -e 's#/mnt/xfs/harvester#/data/harvester#g' \
  -e 's/192\.168\.150\./10.0.99./g' {} +

grep -rn '192\.168\.150\|/mnt/xfs/harvester' scripts/ | head    # 验收:应为空
for f in scripts/*.sh; do bash -n "$f" || echo "语法错误: $f"; done   # ★ 改完必须语法检查

⚠️ VIP 也要跟着换:10.0.99.200 必须落在新网段的 DHCP 池之外 (池是 .100-.199),否则会与动态分配地址冲突。


8. 手工分步部署(等价命令,排障时用)

bash
cd /mnt/xfs/harvester

# 1) 介质(9.5GB,断点续传)
bash scripts/00-download.sh

# 2) 磁盘 / NVRAM / HTTP 符号链接 / DHCP 静态保留
NVME_DISK_DIR=/home/$USER/harvester-disks bash scripts/10-prepare.sh

# 3) HTTP 引导服务
bash scripts/20-http-server.sh

# 4) 装机配置(create/join)+ token + credentials
bash scripts/50-gen-configs.sh

# 5) (建议)探测引导确认设备名
bash scripts/40-define-vm.sh 01 probe
bash scripts/30-console-capture.sh 01 start && virsh start harvester-01
grep -oE 'enp[0-9a-z]+|vd[ab]' logs/harvester-01-console.log | sort -u
virsh destroy harvester-01

# 6) 部署(★ 用 setsid 脱离会话;两个编排器各只能起一个实例)
setsid bash scripts/60-deploy.sh node01 </dev/null >/dev/null 2>&1 &
setsid bash scripts/65-deploy-all.sh    </dev/null >/dev/null 2>&1 &
pgrep -af '60-deplo[y]|65-deplo[y]'
tail -f logs/deploy-all.log

# 7) 验证与收尾
bash scripts/70-verify.sh
bash scripts/75-set-admin-password.sh          # 65 号已自动调用,这里用于复核(幂等)
bash scripts/80-smoke-vm.sh create             # 端到端 VM(见 §9 已知问题)

# 8) 可选:接入内网 Rancher(A~F 六步:跨网桥放行/hook 持久化/内网 DNS/
#    节点 DNS 收敛/containerd 私仓/containerd-registry 设置)
sudo bash scripts/99-rancher-internal-net.sh check
sudo bash scripts/99-rancher-internal-net.sh apply
#    随后按 ../05-接入Rancher与内外网分离解析.md §5 设置 cluster-registration-url 完成导入

9. 已知问题(部署前请知悉)

问题影响状态参考
80-smoke-vm.sh 创建 VM 被 KubeVirt 准入拒绝:doc is missing path: /spec/template/spec/domain/cpu/maxSockets端到端 VM 验证未完成;集群本身健康不受影响❌ 未解决(已定位到 VM spec 缺 domain.cpu 段,候选修法见文档)../02 案例 23
残留 PVC test-vm-disk0default,20Gi,Bound,空卷)占一份 Longhorn 卷,无功能影响⚠️ 待清理(删除命令见 ../02 案例 23)同上
logs/deploy-all.log 末尾是旧版凭据块看日志尾部会拿到过期凭据说明⚠️ 下次部署自动刷新;configs/credentials.txt 为准../03 §6.2
smoke VM 镜像走公网 URL生产不可依赖⚠️ 建议改为内网镜像源../02 案例 23

10. 快速参考卡

bash
# ── 部署 ────────────────────────────────────────────────
bash scripts/run-all.sh --preflight              # 前置检查(安全,不改状态)
setsid bash scripts/run-all.sh </dev/null >/tmp/run-all.log 2>&1 &   # 一键部署
bash scripts/run-all.sh --from configs           # 断点续跑

# ── 观察 ────────────────────────────────────────────────
tail -f logs/deploy-all.log                      # 总编排
tail -f logs/harvester-02-console.log            # 装机串口
cat logs/deploy.status                           # 当前阶段

# ── 验收 ────────────────────────────────────────────────
bash scripts/70-verify.sh                        # 集群 9 项体检
bash scripts/75-set-admin-password.sh; echo rc=$? # rc=0 → dashboard 凭据可用

# ── 访问 ────────────────────────────────────────────────
Dashboard : https://192.168.150.200/     user: admin    password: xxx
SSH       : rancher@192.168.150.11 / .12 / .13   (密钥免密;密码: xxx dashboard 密码)
kubectl   : sudo /var/lib/rancher/rke2/bin/kubectl --kubeconfig /etc/rancher/rke2/rke2.yaml

# ── 自愈(自动,无需干预;手工触发时用这些)────────────────
bash scripts/95-rescue-image-preload.sh 01 run   # L2 预加载卡死救援
bash scripts/96-install-retry.sh 01              # L3 安装器卡死重试
bash scripts/97-installer-netfix.sh 01           # L1 nm-online 注入