跳转至

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%。

双重成因:

  1. 实现无过滤:render_config() 只做 5 个占位符替换,host-vnc 段被下发到全部 14 台;而 filebeat-host.yml.tpl 注释与 SOP.md §9.5 都声称「仅 .28 启用」——代码与文档不一致;
  2. /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 同步,请勿在站点侧修改)