跳转至

SOP — Harbor 预检查「只读探测批量化」改造(probe_batch_20261008)

变更对象:services/harbor/utils/precheck.py(HarborPreCheck.run_all) 变更类型:C 类(改工程代码;只改只读探测的打包方式,判定与文案不动) 撰写:2026-10-08

1. 背景

HarborPreCheck.run_all 对每台 harbor 主机串行执行约 11 个 check。经排查:

  • 通用静态事实(ssh/os/clock/root/selinux/disk_space 等)已由共享库 PreCheckBase.prefetch 合并成「每台一条 shell」,无洼地;
  • 领域专有检查(check_data_mount / check_ports / check_docker_repo / check_upstream / check_cert_material,以及 k8s 侧 check_containerd) 仍在各自方法内用 self._ssh.run(host, 单条命令) 逐项独立往返—— 单台 harbor 主机因此多出 11 条往返(ss/ping/findmnt/6×curl/openssl…), k8s 节点多出 1 条。这是本工程唯一未批量的只读探测洼地。

触发条件:三件套改造(同主机拼一段 shell / 主机间并发 / 进程内探测缓存)已在 共享库与 node_access.py / harbor_host.py 落地,本工程预检查是最后一块。

2. 目标

把领域专有只读探测并入「每台一次 shell」:

  • 可验证状态一:一次 precheck 运行,每台主机恰好 1 条远端 shell (改造前 harbor 主机 12 条、k8s 节点 2 条);
  • 可验证状态二:新旧变更清单(findings)逐条完全一致,报告内容不变;
  • 可验证状态三:判定表达式、findings 文案、skip_checks 过滤、run_all 中 check 的调用顺序一律不动;变更类命令一律不动(本工程预检查全部只读)。

3. 前置条件

  • 操作机 services/harbor/.venv/bin/python 可用;共享库 .pth 已挂载 (precheck_module / paramiko_module / ssh_executor 可导入)。
  • 目标机 root 免密(config/default.yaml 的 nodes),本环境实测可达。
  • 不改共享库:~/py_public_modules/*(precheck_module / base_module 等) 一律不动;本次只复用其既有能力(build_probe_shell / parse_probe_output / PreCheckBase._probe / _probe_cache)。
  • 备份已落盘:probe_batch_20261008/backup/precheck.py(见第 7 章)。

4. 影响范围

  • 主机:1 台 harbor(192.168.31.31)+ 4 台 k8s(192.168.31.10/13/14/15)。
  • 不动服务:仅本地改一个 Python 文件;远端只发只读探测命令,不需停服、 无窗口期。
  • 命令语义不变:main.py precheck / plan / deploy-* / drift 等子命令的 参数、输出与返回码不变(gate/has_block 逻辑未动)。
  • 唯一探测文本变化:3 条 curl 写出口由 -w '%{http_code}' 改为 -w '%{http_code}\n'(原因见第 5 章步骤 4「坑」),取值不变。

5. 分步操作

实现体:utils/precheck.py(HarborPreCheck)。下列命令为人工复现的等价操作, 实际执行以实现体为准。

步骤 1:备份

cd /home/rain/Documents/services/harbor
mkdir -p probe_batch_20261008/backup
cp -p utils/precheck.py probe_batch_20261008/backup/precheck.py
sha256sum utils/precheck.py probe_batch_20261008/backup/precheck.py   # 应一致

预期:两行 sha256 相同;台账见 backup/README.md。失败判断:不一致即重做备份。

步骤 2:改造 precheck.py(每台一次 shell + 本地判定)

新增「只读探测」小节(实现体 utils/precheck.py L66–177):

  • _harbor_probes(host) / _k8s_probes(host):把原有各 check 里的命令原样收拢 成「键 → 命令原文」字典(data_mount / ports_ping / ports_ss / docker_repo / upstream:<domain> / cert_material / containerd);
  • _prefetch_all(hosts):按主机把「static_probes() 通用静态事实 + 领域专有探测」 合并,用共享库 build_probe_shell 拼成一段 shell,同一台一次下发;主机间用 ThreadPoolExecutor 并发(_PROBE_WORKERS=8,超时 _PROBE_TIMEOUT=300);
  • _dprobe(host, key):取样统一入口——命中 _probe_cache 即不再下发,未纳入 批量(独立调用)时单次下发,语义与批量一致;
  • 各 check_* 方法把 self._ssh.run(host, <单条命令>) 换成 self._dprobe(host, "<键>"), 其余判定/文案逐字保留;
  • run_all 在进入角色循环前先 self._prefetch_all(harbor_hosts + k8s_hosts), 并把 role_nodes("k8s") 复用为 k8s_hosts。

坑(本轮上机对照实测抓到):build_probe_shell 在每条命令后跟 echo "@@rc_<键>=$?"。curl -w '%{http_code}' 不输出换行,会让取到的值变成 200@@rc_docker_repo=0 → docker_repo 误判 BLOCK、upstream 误判 WARN。 旧逐条路径无此问题(每次独立往返)。修法:三条 curl 写出口补 \n (-w '%{http_code}\n')。任何经 build_probe_shell 批量化的探测命令都必须以 换行结尾,否则段标记会粘进取值——这是复用共享库批量能力时的通用陷阱。

步骤 3:语法校验

cd /home/rain/Documents/services/harbor
.venv/bin/python -m py_compile utils/precheck.py probe_batch_20261008/selftest.py

预期:无输出、退出码 0。失败判断:报 SyntaxError → 检查改动后重试。

步骤 4:离线自测(不接触远端)

cd /home/rain/Documents/services/harbor
.venv/bin/python probe_batch_20261008/selftest.py

预期:RESULT: PASS(见第 6 章)。失败判断:见第 7 章回滚。

步骤 5:上机新旧对照(只读,可复现)

cd /home/rain/Documents/services/harbor
# 新版存档
cp -p utils/precheck.py /tmp/precheck.new.py
# --- 新版 ---
: > logs/harbor.log
t0=$(date +%s.%N); .venv/bin/python main.py precheck >/tmp/new.out 2>&1; rcn=$?; t1=$(date +%s.%N)
echo "NEW rc=$rcn cmds=$(grep -c 开始执行命令 logs/harbor.log) wall=$(echo "$t1-$t0"|bc)"
cp "$(ls -t reports/precheck-precheck-*.md | head -1)" /tmp/new_report.md
# --- 旧版(用备份覆盖)---
cp -p probe_batch_20261008/backup/precheck.py utils/precheck.py
: > logs/harbor.log
t0=$(date +%s.%N); .venv/bin/python main.py precheck >/tmp/old.out 2>&1; rco=$?; t1=$(date +%s.%N)
echo "OLD rc=$rco cmds=$(grep -c 开始执行命令 logs/harbor.log) wall=$(echo "$t1-$t0"|bc)"
cp "$(ls -t reports/precheck-precheck-*.md | head -1)" /tmp/old_report.md
# --- 立即还原并校验 ---
cp -p /tmp/precheck.new.py utils/precheck.py
cmp -s /tmp/precheck.new.py utils/precheck.py && echo RESTORE_OK || echo RESTORE_FAIL

预期:NEW cmds=5 / OLD cmds=20;RESTORE_OK。命令数取自日志里 开始执行命令(SSHExecutor.run 每次远端调用记一行;日志为追加,测前先 truncate/: > 清空,勿用累计计数)。

6. 验证

  1. 自测(probe_batch_20261008/selftest.py,桩替换远端):
  2. [1] 新旧 findings 逐条一致(new==old,本例 34 条);
  3. [2] 新方案每台恰好 1 条 shell;旧方案 harbor 12 / k8s 2;
  4. [3] 负向对照复现「无 \n 的 curl 写出口粘行」语义(证明桩忠实)。
  5. 上机对照(2026-10-08 实测):
  6. 报告内容一致(忽略「生成时间」行后 diff 为空):两版均 BLOCK 0 / WARN 0 / INFO 34;
  7. 远端命令数 20 → 5(-75%),墙钟 8.44s → 7.52s;
  8. RESTORE_OK 且还原后 sha256 与新版存档一致。
  9. 回归:main.py precheck 返回码、报告结构、gate 判定未变。

7. 回滚

  • 备份位置:probe_batch_20261008/backup/precheck.py(台账 backup/README.md)。
  • 回滚步骤:
cd /home/rain/Documents/services/harbor
cp -p probe_batch_20261008/backup/precheck.py utils/precheck.py
cmp -s probe_batch_20261008/backup/precheck.py utils/precheck.py && echo ROLLBACK_OK
  • 回滚后验证:重跑 main.py precheck,命令数应回到每台 harbor 12 / k8s 2 条。
  • 纯代码回滚,无远端状态残留(本变更不改远端任何东西)。

8. 风险说明

风险 缓解
批量 shell 超时(合并后单条超时) _PROBE_TIMEOUT=300;各 curl 自身仍有 -m 10/20 上限;实测单台 ~7s
单条探测命令无换行 → 段标记粘进取值(已实测发生) 所有经批量的命令以换行结尾;curl 写出口补 \n;selftest 负向对照兜住
把 k8s 探测混到 harbor 主机(角色错配) _domain_probes 按 role_nodes 分派,harbor/k8s 各取所需
探测失败被误判成「通过」 批量解析沿用 _probe_cache_from:rc=-1 记 unknown,各 check 仍按原判据落 WARN/BLOCK
并发过高被 sshd 拒连 _PROBE_WORKERS=8,主机数 5,实测无拒连

附录 A:本文档交付物清单

交付物 路径 说明
变更实现体 services/harbor/utils/precheck.py 改造后(新方案)
备份 probe_batch_20261008/backup/precheck.py 改造前原文件
备份台账 probe_batch_20261008/backup/README.md 原路径/时间/回滚动作
离线自测 probe_batch_20261008/selftest.py 桩替换远端,断言清单一致 + 每台 1 条 shell
本 SOP probe_batch_20261008/SOP.md 本文件
上机报告 reports/precheck-precheck-*.md 新旧两份,内容一致

RUNBOOK:本变更不改动任何面向使用的命令与输出语义,既有 RUNBOOK (../../k8s_ins/ghcr-slow-20261001/RUNBOOK.md)无需更新。

附录 B:实测命令数 · 墙钟

方案 harbor 主机命令数 k8s 节点命令数 合计 墙钟 (s) 报告\n清单
旧(备份) 12 2 20 8.44 BLOCK 0 / WARN 0 / INFO 34
新(本方案) 1 1 5 7.52 BLOCK 0 / WARN 0 / INFO 34
  • 口径:命令数 = logs/harbor.log 中 开始执行命令 行数(每次运行前清空日志); 墙钟 = .venv/bin/python main.py precheck 的实测耗时;清单 = 报告正文(忽略生成时间)。
  • 数据来源:2026-10-08 实测;旧版由 backup/precheck.py 覆盖后运行,跑完已 cmp 校验 RESTORE_OK。

来源:/home/rain/Documents/services/harbor/probe_batch_20261008/SOP.md | 最后更新:2026-10-08 03:18(由 build/sync.py 同步,请勿在站点侧修改)