SOP — EFK vnc 类日志重复采集的收敛¶
主题目录:
vnc-dedup-20261001/| 状态:已实施并验证通过(2026-10-01 22:38) | 2026-10-01 被改工程:monitoring-p2-20261001(EFK 日志聚合与黑盒探测)
1. 背景¶
只读核查(ES 聚合 log_source:vnc)证实:/home/*/.vnc/*.log 被多台主机重复采集。
log_source:vnc文档合计 1,232,870 条,其中 lsf 560,404 / slurm 560,389 / hpc 112,077;- 按主机分布:11 台各约 112,078 条(lsf 5 台 + slurm 5 台 + hpc 1 台),近乎完全相同;
- 按文件路径分布:仅 9 个文件,全部形如
/home/<user>/.vnc/hpc-submit:<N>.log(hpc-submit=.28); - 抽样证死:
/home/cy01/.vnc/hpc-submit:5.log的文档,其host_name是 slurm-master-01。
即:.28 的 9 个 vnc 会话文件(真实约 11.2 万行)被 11 台各采一遍 → 入库 123.3 万条,冗余 90.9%。
双重成因:
- 实现无过滤:render_config() 只做 5 个占位符替换,
host-vnc段被下发到全部 14 台;而 filebeat-host.yml.tpl 注释与 SOP.md §9.5 都声称「仅.28启用」——代码与文档不一致; /home为共享(NFS)挂载:各主机都能读到.28用户家目录下的.vnc/*.log。lustre×2 与 license 未挂/home,故 14 台中只有 11 台中招。
2. 目标¶
| # | 可验证状态 |
|---|---|
| G1 | 14 台主机的 /etc/filebeat/filebeat.yml 中,只有 hpc-submit(.28) 含 host-vnc input,其余 13 台不含 |
| G2 | 收敛后新入库的 log_source:vnc 文档,其 host_name 只有 hpc-submit |
| G3 | .28 的渲染结果与收敛前逐字节一致(不含标记行),其 sha256 不变 → 该台不重启、不断流 |
| G4 | main.py deploy 复跑一次零变更、全跳过(幂等) |
3. 前置条件¶
- 本机:
monitoring-p2-20261001/.venv、~/.kube/config、SSH 凭据(由共享库paramiko_module处理,无需接触 secrets); - ES 可查:
http://192.168.31.10:9200(Basic 认证,凭据set -a; . ~/.secrets/efk.env; set +a); - 变更前备份(见第 7 章):
artifacts/filebeat-host.yml.tpl、modules/host_filebeat.py、config/default.yaml。
4. 影响范围¶
| 项 | 说明 |
|---|---|
| 涉及主机 | 集群外 14 台(.16–.29);其中 13 台配置发生变化 → 重启 filebeat |
| 是否停服 | 否。filebeat 重启期间该主机日志有秒级断流(seek: tail 只采新条目,断流期日志行会永久丢失) |
| 业务影响 | 无。filebeat 不参与计算,与 Slurm/LSF/Lustre 作业无关 |
| K8s 侧 | 不受影响(本变更只改集群外主机的渲染逻辑,不触碰 DaemonSet 与 ConfigMap) |
| 存量数据 | 已入库的约 123 万条重复文档不自动消失,默认随 ILM 14 天滚动删除;立即清理见 5.6(高危、可选) |
| 窗口期 | 无作业时段建议(断流丢日志的窗口最小化),非强制 |
5. 分步操作¶
实现体:monitoring-p2-20261001/modules/host_filebeat.py(入口 main.py {precheck|verify|deploy|drift})。
以下为与实现体等价的操作序列,供复核与手工复现。
5.1 备份¶
cd ~/Documents/k8s_ins
TS=20261001-223542 # 实际执行时的时间戳
mkdir -p vnc-dedup-20261001/backup/monitoring-p2-20261001/{artifacts,modules}
cp monitoring-p2-20261001/artifacts/filebeat-host.yml.tpl \
vnc-dedup-20261001/backup/monitoring-p2-20261001/artifacts/filebeat-host.yml.tpl.bak.$TS
cp monitoring-p2-20261001/modules/host_filebeat.py \
vnc-dedup-20261001/backup/monitoring-p2-20261001/modules/host_filebeat.py.bak.$TS
chmod 600 vnc-dedup-20261001/backup/monitoring-p2-20261001/*/*.bak.$TS
预期:两个 .bak 生成(5245 B / 13598 B);已登记到本主题 backup/README.md。
备份位置按全局规则放本主题 backup/(保持原路径层次),不散落在被改文件旁。
5.2 模板:给 host-vnc 段加可剥离标记¶
artifacts/filebeat-host.yml.tpl 中,在 host-vnc input 前后各加一行标记(缩进两空格,与其他 input 同级):
+ # >>> host-vnc (rendered only on the graphic-session host) >>>
- type: filestream
id: host-vnc
enabled: true
paths:
- /home/*/.vnc/*.log
fields: { ... }
fields_under_root: true
prospector.scanner.check_interval: 30s
+ # <<< host-vnc <<<
为什么用标记而非拆分模板:标记由渲染器统一剥离——非目标主机连同标记一起删除,目标主机保内容、去标记,从而 .28 的最终文本与收敛前逐字节一致(满足 G3,避免无谓重启)。
5.3 渲染:按节点角色过滤¶
modules/host_filebeat.py 的 render_config() 末尾增加剥离逻辑(role 取 submit,语义为「图形会话提交节点」):
def render_config(self, node, cluster, filebeat_password):
tpl = TEMPLATE.read_text(encoding="utf-8")
- return (tpl
- .replace("__CLUSTER__", cluster)
- .replace("__ROLE__", node["role"])
- .replace("__HOST_NAME__", node["name"])
- .replace("__ES_HOST__", self.fb["es_host"])
- .replace("__FB_PASSWORD__", filebeat_password))
+ out = (tpl
+ .replace("__CLUSTER__", cluster)
+ .replace("__ROLE__", node["role"])
+ .replace("__HOST_NAME__", node["name"])
+ .replace("__ES_HOST__", self.fb["es_host"])
+ .replace("__FB_PASSWORD__", filebeat_password))
+ return self._strip_vnc_block(out, keep=(node["role"] == VNC_ROLE))
+
+ def _strip_vnc_block(self, text: str, keep: bool) -> str:
+ """剥掉 host-vnc 段与其标记行;keep=True 时只去标记、保内容。"""
+ out, skip = [], False
+ for line in text.splitlines(keepends=True):
+ if VNC_BEGIN in line:
+ skip = not keep # keep=True(submit 主机)→ 保留中间内容
+ continue
+ if VNC_END in line:
+ skip = False
+ continue
+ if not skip:
+ out.append(line)
+ return "".join(out)
模块级常量:
VNC_ROLE = "submit" # 图形会话提交节点(当前仅 hpc-submit/.28)
VNC_BEGIN = "# >>> host-vnc"
VNC_END = "# <<< host-vnc"
坑:config/default.yaml 的 filebeat.log_paths 只列了 messages/secure,不含 vnc,故无需改配置——采集面由模板决定,别去配置里找开关。
5.4 本地自测(不上机)¶
用 14 台的真实节点字典逐个渲染,断言只有 hpc-submit 含 host-vnc:
cd ~/Documents/k8s_ins/monitoring-p2-20261001
.venv/bin/python - <<'PY'
import yaml
from modules.host_filebeat import HostFilebeat
cfg = yaml.safe_load(open("config/default.yaml"))
fb = HostFilebeat(cfg)
bad = []
for cluster, nodes in cfg["nodes"].items():
for n in nodes:
out = fb.render_config(n, cluster, "DUMMY")
has = "host-vnc" in out
if has != (n["role"] == "submit"):
bad.append((n["name"], has))
print("不符合预期的节点:", bad or "无")
PY
预期:不符合预期的节点: 无。
失败判断:出现任何节点 → 回到 5.3 检查正则/缩进,不得上机。
5.5 上机收敛¶
cd ~/Documents/k8s_ins/monitoring-p2-20261001
.venv/bin/python main.py precheck # 前置检查(快门禁)
.venv/bin/python main.py deploy --dry-run # 预演:须实测零改动
.venv/bin/python main.py deploy # 实际收敛:仅 13 台变更 + 重启
预期:13 台出现 write-config,start-service;hpc-submit 显示跳过(G3 生效)。
失败判断:.28 也报变更 → 说明 5.2/5.3 的剥离不彻底,回第 7 章回滚后修正。
5.6 存量重复文档清理(高危;已于 2026-10-01 22:44 执行)¶
原本可交由 ILM efk-14d 在 14 天内滚掉;本次按用户要求立即清理。先只数不删:
# 只读:统计将被删除的文档数(预期约 1,120,000)
curl -s -u "elastic:$ELASTIC_PASSWORD" \
'http://192.168.31.10:9200/filebeat-host-*/_search?pretty' \
--data-raw '{"size":0,"track_total_hits":true,
"query":{"bool":{"must":[{"term":{"log_source":"vnc"}}],
"must_not":[{"term":{"host_name":"hpc-submit"}}]}}}'
确认数字无误后再执行 _delete_by_query(高危:不可逆、不可回滚,须先确认 ILM 未同时删除,并记录删除前后的文档数)。
6. 验证¶
| # | 检查 | 命令 | 预期 |
|---|---|---|---|
| V1 | 配置面收敛 | for h in 16 17 18 19 20 21 22 23 24 25 26 27 28 29; do echo -n ".$h "; ssh root@192.168.31.$h 'grep -c "id: host-vnc" /etc/filebeat/filebeat.yml'; done |
.28 = 1,其余 = 0 |
| V2 | 服务健康 | ssh root@192.168.31.28 'systemctl is-active filebeat' |
active(13 台同) |
| V3 | 数据面收敛(等待一个新批次后) | ES:log_source:vnc 按 host_name 聚合 |
仅 hpc-submit,无 lsf/slurm 域 |
| V4 | 幂等 | .venv/bin/python main.py deploy 再跑一次 |
14 台全跳过、零变更 |
| V5 | 漂移 | .venv/bin/python main.py drift |
无漂移 |
V3 须在新文档产生后判读(filebeat 重启后的新条目);历史重复文档不影响该判据。
实测结果(2026-10-01 22:38–22:40)¶
| # | 预期 | 实测 |
|---|---|---|
| V1 | .28 = 1,其余 = 0 |
✅ 14 台逐一核对:hpc-submit host-vnc=1,其余 13 台 =0 |
| V2 | 14 台 active |
✅ 全部 active |
| V3 | 新文档仅 hpc-submit |
✅ 本地 22:39:00 之后仅 hpc-submit(42 条);14:38Z 起出现的少量 lsf/slurm 文档均为各台重启瞬间(22:38:03–13)的最后残留,此后不再产生 |
| V4 | 复跑零变更 | ✅ 22:38:58 复跑:14 台全部 -> OK(无 actions)、失败 0 |
| V5 | 无漂移 | ✅ main.py drift rc=0、无漂移输出 |
收敛动作:13 台 write-config,start-service;hpc-submit 无动作(G3 的逐字节一致生效,未重启、无断流);汇总「14 台处理,失败 0 台」。
实施中发现并已修的缺陷:_strip_vnc_block() 首版漏用 keep 参数(skip = True),导致 submit 主机也被整段删除。本地自测即刻暴露:G3 断言不一致(旧 4228 B vs 新 3963 B,差额 265 B 正是该段内容)。改为 skip = not keep 后自测四绿。该缺陷在上机前被拦下,未产生任何生产影响——这是"先本地断言、再上机"的直接收益。
存量数据:待删 1,123,313 条(log_source:vnc 且 host_name != hpc-submit)已于 2026-10-01 22:44 通过 _delete_by_query 清理 —— deleted=1,123,313、version_conflicts=0、failures=[]、耗时 86 s。清理后 log_source:vnc 仅剩 112,635 条(全部来自 hpc-submit,仍在正常增长);hpc-submit 的数据全程未受影响。
7. 回滚¶
失败判据(任一达标即回滚):任一主机 filebeat 非 active;.28 出现非预期的配置变更;V1 中 13 台未全部收敛。
cd ~/Documents/k8s_ins/monitoring-p2-20261001
cp backup/filebeat-host.yml.tpl.bak.<TS> artifacts/filebeat-host.yml.tpl
cp backup/host_filebeat.py.bak.<TS> modules/host_filebeat.py
.venv/bin/python main.py deploy # 重新下发:14 台恢复含 host-vnc 的旧配置
回滚后验证:V1 全为 1、V2 全 active、.venv/bin/python main.py deploy 复跑零变更。
备份位置:本主题 backup/(见 vnc-dedup-20261001/backup/README.md);上机前还须在工程 monitoring-p2-20261001/backup/ 登记本节 5.1 产生的两个 .bak。
8. 风险说明¶
| 风险 | 缓解 |
|---|---|
剥离逻辑误删相邻 input(如 host-flexlm)→ YAML 非法 → 启动失败 |
5.4 本地断言 + 5.5 --dry-run + 上机后 systemctl is-active |
.28 被误改触发无谓重启与断流 |
G3 的逐字节一致设计 + 5.5 预期判读 |
重启造成秒级日志丢失(seek: tail 不补历史) |
选无作业时段执行;断流窗口最小化 |
_delete_by_query 误删 |
5.6 先只数不删;确认数字后再执行;不做无边界通配 |
| 文档与代码再次漂移 | 实施后同步更新 monitoring-p2-20261001/docs/SOP.md §9.5(把「仅 .28」从注释变成实现事实)与 docs/RUNBOOK.md |
附录 A:交付物清单¶
| 文件 | 说明 |
|---|---|
SOP.md |
本文件(方案;实施后补实施记录与实测) |
backup/README.md |
docs/HANDOFF.md 定点修订的留痕与回滚依据 |
附录 B:同族风险(未查,超本次范围)¶
同一模板的 domain 段含 NFS 路径 /data/nfs/lsf/*/logdir/*.log。若该路径同样跨主机共享,lsf 领域日志可能存在同族重复,建议单独立项核查(判据同本次:按 host_name 与 log.file.path 聚合比对)。
来源:
/home/rain/Documents/k8s_ins/vnc-dedup-20261001/SOP.md| 最后更新:2026-10-01 22:46(由build/sync.py同步,请勿在站点侧修改)