跳转至

SOP — 日志 ↔ 指标互跳(第一阶段:静态互跳 + 裸主机名标签)

主题目录:log-metrics-crosslink-20261002/ | 负责人:运维 | 日期:2026-10-02 关联:docs/LOGGING-GAP.md #1(对齐键)、docs/HANDOFF.md §3.1 组一 #1

1. 背景

LOGGING-GAP #1「日志 ↔ 指标互跳」经 2026-10-02 实机核对,确认两侧无单一通用对齐键, 且存在一个格式差:指标侧主机标识是 instance="<主机名>:9100",日志侧是 host.name="<主机名>"。 Grafana 的跳转链接无法在 URL 里剥掉 :9100,故先给指标补一个裸主机名标签 hostname, 再在两侧各加一个静态入口链接(不做带选中值的动态 drilldown,那属第二阶段)。

2. 目标

可验证的完成状态:

  1. 14 台集群外主机的 up 序列携带 hostname 标签,取值等于裸主机名(无端口);
  2. Grafana 5 个环境大盘出现「查看日志(Kibana)」链接,可达 kibana.rainchen.top 日志分域视图;
  3. Kibana「日志分域视图」出现「查看指标(Grafana)」面板,内含 5 个域大盘链接;
  4. 两侧 drift 退出码为 0,幂等复跑零变更。

3. 前置条件

  • 环境:本机 192.168.31.249,可 root 免密 ssh 到 14 台主机;kubectl 指向 ~/.kube/config。
  • 凭据:~/.secrets/efk.env(KIBANA_SYSTEM_PASSWORD 等),由工程内部读取,不得 cat。
  • 工程:env-monitor-deploy(Grafana 大盘/指标)、monitoring-p2-20261001(Kibana/EFK)。
  • 执行前检查:两侧 main.py drift 均无待变更项(确认基线干净)。 bash cd /home/rain/Documents/k8s_ins/env-monitor-deploy && .venv/bin/python main.py drift; echo "RC=$?" cd /home/rain/Documents/k8s_ins/monitoring-p2-20261001 && .venv/bin/python main.py drift; echo "RC=$?" 预期:两条 RC=0;有非零先查清再动手。

4. 影响范围

  • 主机与组件:14 台集群外主机(Slurm/Lustre/LSF/HPC/FlexLM)的 抓取标签、5 个 Grafana 环境大盘、 Kibana 1 个仪表板 + 1 个新增 saved object。
  • 是否停服:否。不改采集链路(Filebeat 与 node-exporter 均不动),仅改 Prometheus 目标标签与展示层。
  • 窗口期:无特别要求,任一时刻可执行(本工程 deploy 幂等、可回滚)。
  • 在跑业务:不影响;指标查询在 relabel 变更后有约 5 分钟的新旧序列并存期(见第 6 章)。

5. 分步操作

步骤 1:指标侧增加 hostname 裸主机名标签

ServiceMonitor 的 relabel 规则由实现体按配置逐台生成,hostname 与 cluster/role 并列, 取值即配置里的 nodes[].name(与日志侧 host.name 同源)。改动只有一处元组: env-monitor-deploy/modules/k8s_ingest.py 的 _render_one()。

坑:模板 01-external-node-exporters.yaml.tpl 的头部注释同时声明了「每台几条 relabel」, 改了生成逻辑必须同步注释,否则下一个读者按注释核对会误判。

cd /home/rain/Documents/k8s_ins/env-monitor-deploy
# 修改点:modules/k8s_ingest.py 的 relabel 元组增加 ("hostname", name)
#         manifests/01-external-node-exporters.yaml.tpl 注释「三条」→「四条」
.venv/bin/python main.py deploy

实现体:modules/k8s_ingest.py(_render_one → relabel 行)。 预期:抓取目标全部 up 达成:14/14;kubectl get servicemonitor external-node-exporters 的 relabelings[*].targetLabel 中出现 hostname。 失败判断:up 数不足 14 → 第 7 章回滚。

步骤 2:Grafana 大盘增加「查看日志(Kibana)」链接

大盘走「精简源 + 生成器」,链接写进精简源的顶层 extra.links,由生成器透传到大盘 JSON。

坑(本次实际踩到):overview.yaml 原本已有顶层 extra(内容为 version: 1)。 YAML 同名顶层键后写覆盖先写、且不报错,直接再写一个 extra: 会让新加的 links 被静默丢弃 (表现为 build-dashboards 报「未变」,链接根本没进产物)。必须把 links 合并进已有的 extra。

cd /home/rain/Documents/k8s_ins/env-monitor-deploy
# 修改点:dashboards/{overview,slurm,lustre,lsf,flexlm}.yaml
#   overview  → 在已有的 extra(version: 1)下追加 links
#   其余 4 个 → 新增 extra.links
.venv/bin/python main.py build-dashboards --check   # 预期 5 个精简源各报 1 处差异
.venv/bin/python main.py build-dashboards           # 预期 5 个「已生成」
.venv/bin/python main.py deploy

实现体:utils/dashboard_builder.py(extract 收集 extra、render 透传)。 预期:5 个 manifests/*-dashboard.yaml 各含 1 处 kibana.rainchen.top。 失败判断:--check 报「未变」而文件确实改过 → 检查是否有重复顶层 extra。

步骤 3:Kibana 侧新增「查看指标(Grafana)」面板

新增一个 legacy visualization + visState.type: markdown 的 saved object(8.19 仍支持), 并在分域视图仪表板的 panels 数组挂为 p10。仪表板的 references 由 main.py kibana 按 ref 自动构建,不需要手写。

坑:visState 是字符串化的 JSON,其中的换行要写成 \\n、引号要写成 \"; 写错不会报错,只会在 Kibana 渲染成空白或乱码。

cd /home/rain/Documents/k8s_ins/monitoring-p2-20261001
# 新增  kibana/saved_objects/12-markdown-metrics-links.json
# 修改  kibana/saved_objects/06-dashboard-domain-overview.json(panels 加 p10:x0 y64 w48 h8)
.venv/bin/python main.py kibana --dry-run    # 预期:dashboard pending + visualization pending
.venv/bin/python main.py kibana              # 预期:已写入 2 个对象 + 复检通过

实现体:main.py kibana(main.py kibana → Kibana saved objects API)。 预期:复检通过:2 个对象均已与声明一致。 失败判断:pending 反复不消 → 检查 visState 转义与 ref/id 是否与仪表板一致。

6. 验证

# 1) hostname 标签 14/14(带 instance 区分新旧序列,避免被 stale 序列误导)
kubectl -n monitoring exec prometheus-kube-prometheus-stack-prometheus-0 -c prometheus -- \
  promtool query instant http://localhost:9090 'count(up{job="external-node-exporters", hostname!=""})'
#    预期:{} => 14

# 2) 大盘 links 已入产物与集群对象
kubectl -n monitoring get cm env-monitor-overview -o jsonpath='{.data}' | grep -c 'kibana.rainchen.top'
#    预期:1

# 3) Kibana 对象一致(复跑应全部 done)
cd /home/rain/Documents/k8s_ins/monitoring-p2-20261001 && .venv/bin/python main.py kibana

# 4) 两侧漂移检测退出码
cd /home/rain/Documents/k8s_ins/env-monitor-deploy && .venv/bin/python main.py drift; echo "RC=$?"
cd /home/rain/Documents/k8s_ins/monitoring-p2-20261001 && .venv/bin/python main.py drift; echo "RC=$?"
#    预期:两条 RC=0

# 5) 幂等复跑:第二次 deploy / kibana 应零变更

注意(本次实测):relabel 变更后,Prometheus 会同时保留旧序列(无 hostname)约 5 分钟, 期间 count by (hostname) 会看到「空桶 + 带标签桶」并存,属正常;用 hostname!="" 过滤即可得真值。

UI 渲染验证:浏览器打开 https://kibana.rainchen.top 的「日志分域视图」,确认底部出现 「查看指标(Grafana)」;Grafana 任一大盘右上角出现「查看日志(Kibana)」。此项由用户确认 (内网自签证书下无头浏览器验证代价高)。

7. 回滚

回滚即用备份覆盖原文件,再重跑对应下发。

回滚对象 备份位置 回滚动作
env-monitor-deploy 的 3 类文件 backup/env-monitor-deploy/... 覆盖后 build-dashboards + deploy
monitoring-p2 的 06 仪表板 backup/monitoring-p2-20261001/... 覆盖后 main.py kibana
新增 12-markdown 面板 无备份(全新文件) 删除该文件 + 回滚 06,再 main.py kibana

备份结构与台账见 backup/README.md。

回滚后验证:drift 退出码 0;count(up{job="external-node-exporters", hostname!=""}) 归零; 大盘 ConfigMap 不再含 kibana.rainchen.top。

回滚触发判据(量化,任一成立即回滚):① drift 退出码非 0;② 抓取目标 up 数 < 14; ③ 大盘或 Kubana 面板渲染异常导致原布局不可用。

8. 风险说明

风险 缓解
改 ServiceMonitor 影响 14 台主机抓取 工程 deploy 幂等且有 drift 门禁;失败即回滚(判据见第 7 章)
YAML 重复顶层键静默覆盖 改精简源后必跑 --check,并在产物中 grep 关键字确认落地
stale 序列造成「标签没生效」误判 验证用 hostname!="" 过滤,或等待 >5 分钟
静态链接不带当前选中主机/服务 已在面板与本文档标明为第一阶段;动态 drilldown 需先取得 Kibana 格式,列入第二阶段
Kibana markdown 为 legacy 可视化,未来版本可能移除 已记录为依赖项;若升级 Kibana 需回归此面板

9. 第二阶段:动态互跳与服务目录(2026-10-02)

9.1 背景与目标

第一阶段只做了两侧静态入口链接(不带当前选中值),且未解决「服务」维度的对齐。 本阶段补上三块,闭环 LOGGING-GAP #1:

  1. Grafana → Kibana(动态):环境大盘的主机 Top15 面板加 data link,点击某个主机 直接带 host.name 打开 Kibana 日志分域视图;
  2. Kibana → Grafana(动态):Kibana 侧新增声明式 Vega 面板,按主机聚合日志量, 点击柱形打开该主机所属域的 Grafana 大盘(带 var-cluster);
  3. 服务目录映射表:cluster / service.name → 指标侧定位(service-catalog.yaml)。

可验证的完成状态:① 两侧 drift 退出码 0、幂等复跑零变更;② Grafana 大盘出现 3 处「查看该主机日志(Kibana)」data link;③ Kibana 分域视图出现 p11「按主机日志量」面板。

9.2 关键技术结论(务必先读)

  • Kibana 8.19 无法用 API 创建 URL drilldown:/api/saved_objects/drilldown、 url-drilldown 等一律返回 Unsupported saved object type;urlDrilldown 插件虽为 available,但 drilldown 内联在 dashboard 面板的 embeddableConfig.enhancements.dynamicActions, 没有公开创建 API(新版 /api/dashboards 亦未启用)。故改用声明式 Vega 面板实现 Kibana → Grafana 跳转。
  • Kibana 自签证书 + strict security 使无头浏览器不可用:内置浏览器报 ERR_CERT_AUTHORITY_INVALID;改经 kubectl port-forward 走 HTTP 后,Kibana 又以 「strict security requirements」拒绝非 HTTPS 会话。渲染类验证只能由人工在浏览器完成(见 9.4)。
  • K8s 侧 host.name 是 Filebeat Pod 名(filebeat-xxxxx),不是主机名,且无 cluster 字段; Vega 面板因此过滤掉无域标签的桶,只保留集群外主机。
  • 服务名是「进程/单元」粒度:实测 service.name 取值多为 systemd/sshd/crond/lmgrd 等单元或进程名,指标侧无同名字段,故服务维度经「域」转发到指标大盘。

9.3 分步操作(变更点)

# 变更点 文件 下发
1 Vega 面板声明文件(由脚本生成,避免双重转义) build-vega-panel.py → monitoring-p2-20261001/kibana/saved_objects/13-vega-host-metrics.json main.py kibana
2 仪表板挂载 p11 面板 monitoring-p2-20261001/kibana/saved_objects/06-dashboard-domain-overview.json main.py kibana
3 3 个主机 Top15 面板加 data link;CPU 面板查询补 hostname 标签 env-monitor-deploy/dashboards/overview.yaml build-dashboards → deploy
4 服务目录映射表(新增) log-metrics-crosslink-20261002/service-catalog.yaml 无(数据源 / 文档)
# Kibana 侧
cd /home/rain/Documents/k8s_ins/log-metrics-crosslink-20261002 && python3 build-vega-panel.py
cd /home/rain/Documents/k8s_ins/monitoring-p2-20261001
.venv/bin/python main.py kibana --dry-run    # 预期:dashboard + visualization 各 pending
.venv/bin/python main.py kibana

# Grafana 侧
cd /home/rain/Documents/k8s_ins/env-monitor-deploy
.venv/bin/python main.py build-dashboards && .venv/bin/python main.py build-dashboards --check
.venv/bin/python main.py deploy

坑:① Vega 的 visState 与其内 params.spec 是双层字符串,必须用脚本生成,手写转义极易出错; ② host.name 在 K8s 侧是 Pod 名,聚合须过滤无 cluster 的桶,否则榜单被 Filebeat Pod 挤占; ③ Grafana data link 用 ${__field.labels.hostname},被聚合掉 hostname 的查询(如 CPU 的 avg by (instance, cluster))必须先补回 hostname,否则链接取不到值; ④ Kibana 的 _g filter 必须带 meta 段:meta:(alias:!n,disabled:!f,index:efk-all-logs, key:host.name,negate:!f,params:(query:'<值>'),type:phrase) 外加 query:(match_phrase:(host.name:'<值>'))。 只写 query 段会被 Kibana 判为「Filter value is invalid or incomplete」,所有面板变空 —— 2026-10-02 实测踩到并修正; ⑤ 三个主机 Top15 的查询必须带 job="external-node-exporters":cluster / role 标签在 集群内 node-exporter(4 个 k8s 节点)与 external-node-exporter(单数,192.168.31.250) 上同样存在,只按 cluster/role 过滤会混入无 hostname 标签的序列;点中这类 bar 时链接取空, 表现为 Kibana 侧显示 host.name: (empty)、面板全空。2026-10-02 实测修正; ⑥ data link 变量只能用 ${__field.labels.hostname},不要用 ${__field.name}: 后者在 bargauge 中返回的是 Grafana 内部默认字段名 Value(实测 Kibana 侧显示 host.name: Value)。 legendFormat: '{{hostname}}' 只影响显示、与取值无关;链路取值靠 __field.labels, 故必须保证被点的序列带 hostname 标签(即坑 ⑤ 的 job 过滤是取值的前提)。2026-10-02 实测; ⑦ Vega 面板打开外部 URL 需显式开启:Kibana 默认禁外链,p11 面板顶部会红字提示 「External URLs are not enabled. Add vis_type_vega.enableExternalUrls: true to kibana.yml」。 本工程以环境变量注入(manifests/11-kibana.yaml):VIS_TYPE_VEGA_ENABLEEXTERNALURLS=true。 ⚠ 改后 Kibana 会重启(Deployment 为 Recreate 策略,约 1~2 分钟入口不可用)。2026-10-02 实施。

9.4 验证

# 1) Grafana 产物含 3 处 data link
kubectl -n monitoring get cm env-monitor-overview -o jsonpath='{.data}' | grep -c '查看该主机日志(Kibana)'   # 预期 3
# 2) node_* 指标普遍带 hostname 标签
kubectl -n monitoring exec prometheus-kube-prometheus-stack-prometheus-0 -c prometheus -- \
  promtool query instant http://localhost:9090 'count(node_cpu_seconds_total{hostname!=""})'   # 预期 592
# 3) Vega 对象存在
kubectl -n monitoring exec elasticsearch-0 -- bash -lc \
  'E="elastic:$ELASTIC_PASSWORD"; curl -s -u "$E" -H "kbn-xsrf: true" "http://kibana:5601/api/saved_objects/visualization/efk-vega-host-metrics"'
# 4) 两侧幂等:第二次 deploy / kibana 零变更;drift 均 rc=0

UI 渲染验证(须人工,原因见 9.2): - Grafana 环境总览大盘 →「CPU/内存/根分区使用率 Top15」→ 悬停柱形应出现「查看该主机日志(Kibana)」, 点击打开 Kibana 分域视图并已按该主机过滤; - Kibana 日志分域视图 → 底部 p11「按主机日志量」→ 点击柱形应打开对应域 Grafana 大盘(带 var-cluster)。

9.5 回滚

回滚对象 备份位置 回滚动作
env-monitor-deploy/dashboards/overview.yaml backup/env-monitor-deploy/dashboards/... 覆盖后 build-dashboards + deploy
monitoring-p2-20261001/.../06-dashboard-domain-overview.json backup/monitoring-p2-20261001/kibana/saved_objects/... 覆盖后 main.py kibana
新增 13-vega-host-metrics.json / service-catalog.yaml / build-vega-panel.py 无(全新文件) 删除 13-*.json、回滚 06,再 main.py kibana

回滚触发判据(任一成立即回滚):① 两侧 drift 退出码非 0;② 大盘或 Kibana 面板渲染异常 导致原布局不可用;③ 抓取目标 up 数 < 14。

10. 第三阶段:服务目录本土化 + 「服务 · 作业 · 主机」一张页(2026-10-02)

10.1 背景与目标

第二阶段遗留两条:① 服务维度只经「域」转发,未做「进程名 → 业务服务」归类; ② 指标与日志各有短板(Grafana 无日志数据源、Kibana 无指标),无法从「服务」这一层切入。 本阶段做两件事:

  1. 服务目录本土化:service-catalog.yaml 新增 business_services 段,把日志侧 service.name 的进程/单元粒度归并为业务服务(13 个),并给出该服务的域 / 主机名正则 / 进程取值 / 指标盘 uid / Kibana 过滤键值;
  2. 统一入口盘:Grafana 新建 env-service-map「服务 · 作业 · 主机(统一入口)」 (4 组 13 面板 + svc / host 两级级联变量),同一页看服务健康、作业与主机资源, 日志一律经 Kibana 链接下钻。

可验证的完成状态:① deploy 首次下发成功、幂等复跑零变更、drift rc=0; ② Grafana sidecar 写入 env-service-map-dashboard.json;③ 环境总览出现新盘 link。

10.2 关键技术结论(先读)

  • 指标侧没有 service.name 对应字段(第二阶段已记):服务 → 指标只有两条路 —— 集群外主机按 hostname 正则,K8s 平台服务按 kubernetes.namespace(kube_* 指标)。 故新盘的「服务」变量是 custom 类型(显示名 : 主机正则),不是指标派生变量。
  • hostname 标签只加在 job="external-node-exporters"(复数)上。2026-10-02 实测 Prometheus 中 node_cpu_seconds_total 分属三个 job:external-node-exporters(14 台,有 hostname)、external-node-exporter(单数,宿主 192.168.31.250,无 hostname)、 node-exporter(4 台 K8s 节点,无 hostname)。故新盘主机/服务面板只覆盖 14 台 集群外主机;宿主与 K8s 节点走「服务目录」表里的链接进入既有盘。
  • Grafana 侧看不到日志:所有日志入口是 Kibana 链接,且 markdown 表格里的 URL 必须把 rison 的括号编码为 %28 / %29,否则 markdown 链接会在第一个 ) 处截断。
  • dashboard description 只能写在精简源的 extra 段:dashboard_builder.render() 只识别 固定的顶层键(manifest/configmap/title/uid/tags/timezone/refresh/time/variables/groups), 写在顶层的 description 会被静默丢弃。
  • svc 变量与目录同源:service-catalog.yaml 的 business_services[].hosts_filter 必须与精简源 svc 变量的选项值一一对应 —— 改其一必须同步另一处(无自动校验,属已知双轨)。

10.3 分步操作(变更点)

# 变更点 文件 下发
1 新增新盘精简源(uid env-service-map,4 组 13 面板) env-monitor-deploy/dashboards/service-map.yaml build-dashboards → deploy
2 生成物(禁止手改,check_sync 门禁会拦) env-monitor-deploy/manifests/15-env-service-map-dashboard.yaml 同上
3 kubernetes.manifests 列表注册新盘 env-monitor-deploy/config/env-monitor.yaml 同上
4 环境总览加「服务 / 作业 / 主机(统一入口)」link env-monitor-deploy/dashboards/overview.yaml 同上
5 服务目录本土化(business_services 段,13 个业务服务) log-metrics-crosslink-20261002/service-catalog.yaml 无(数据源 / 文档)
cd /home/rain/Documents/k8s_ins/env-monitor-deploy
.venv/bin/python main.py build-dashboards && .venv/bin/python main.py build-dashboards --check
.venv/bin/python main.py deploy        # 首次下发
.venv/bin/python main.py deploy        # 幂等复跑:应零变更、全跳过
.venv/bin/python main.py verify && .venv/bin/python main.py drift

坑:① 新盘 svc 变量是 custom(含 includeAll: false),host 变量依赖 $svc (label_values(up{job="external-node-exporters", hostname=~"$svc"}, hostname))构成级联 —— 若把 svc 写成 query 变量,级联不成立;② 主机面板的 Kibana data link 仍需 job="external-node-exporters" 与 ${__field.labels.hostname}(第二阶段坑 ⑤⑥ 在此盘同样适用); ③ 空数据面板要显式 or vector(0)(如「副本不可用的 Deployment」无异常时返回空集, Grafana 会显示 "No data" 而非 0)。

10.4 验证(2026-10-02 实测)

# 1) 新盘 ConfigMap 已落地且带 Grafana sidecar 标签
kubectl -n monitoring get cm env-service-map-dashboard -o jsonpath='{.metadata.labels}'   # grafana_dashboard=1
# 2) Grafana 已真的加载该盘(**写文件 ≠ 已加载**,必须走 API 确证)
kubectl -n monitoring port-forward svc/kube-prometheus-stack-grafana 13000:80 &
U=$(kubectl -n monitoring get secret grafana-admin -o jsonpath='{.data.admin-user}' | base64 -d)
P=$(kubectl -n monitoring get secret grafana-admin -o jsonpath='{.data.admin-password}' | base64 -d)
curl -s -o /dev/null -w '%{http_code}\n' -u "$U:$P" http://localhost:13000/api/dashboards/uid/env-service-map   # 预期 200
curl -s -u "$U:$P" "http://localhost:13000/api/search?tag=env-monitor" | grep -o '"title":"[^"]*"'               # 应含「服务 · 作业 · 主机(统一入口)」
#    2026-10-02 实测:uid 查询 200(created 05:27:51Z),tag 查询返回 6 个盘含新盘
# 3) 环境总览已带新盘入口
kubectl -n monitoring get cm env-monitor-overview -o jsonpath='{.data}' | grep -c '服务 / 作业 / 主机(统一入口)'   # 预期 1
# 4) 幂等与漂移
#    第二次 deploy:变更执行 0 次,k8s_ingest 状态 skipped;verify rc=0;drift rc=0

⚠ 验证取数坑:① Grafana 的 admin 凭据在 secret grafana-admin(keys admin-user / admin-password), 不是 kube-prometheus-stack-grafana —— 用错会得到 401 password-auth.failed; ② dashboard sidecar 写入文件后会主动 POST /api/admin/provisioning/dashboards/reload, 故写入即触发加载,不必等 updateIntervalSeconds; ③ Grafana 容器是精简镜像(无 sh / ls),不能进容器查 /tmp/dashboards,只能从 sidecar 日志或 API 侧取证; ④ GET /api/search?query=<关键字> 对中文标题匹配不可靠(实测 query=service 返回 []), 按 tag 或 uid 查询才稳。

UI 渲染验证(须人工,原因见 §9.2): - https://grafana.rainchen.top/d/env-service-map → 切「业务服务」变量,确认「主机」变量选项随之收敛、 「主机资源」三块柱形出数、点柱形可跳 Kibana 且已按该主机过滤; - 「服务目录」表内每行的「指标」「日志」链接可点通; - 环境总览右上角出现「服务 / 作业 / 主机(统一入口)」。

10.5 回滚

回滚对象 备份位置 回滚动作
env-monitor-deploy/dashboards/overview.yaml backup/env-monitor-deploy/dashboards/overview.yaml.bak.20261002-132502 覆盖后 build-dashboards + deploy
env-monitor-deploy/config/env-monitor.yaml backup/env-monitor-deploy/config/env-monitor.yaml.bak.20261002-132502 覆盖后 build-dashboards + deploy
新增 dashboards/service-map.yaml、manifests/15-*.yaml、service-catalog.yaml 的 business_services 段 无(全新 / 纯增量) 删除 service-map.yaml 与 manifests/15-*.yaml,config 去掉该条目后 build-dashboards + deploy;或 kubectl -n monitoring delete cm env-service-map-dashboard

回滚触发判据(任一成立即回滚):① deploy 返回非 0 或 drift rc≠0; ② 新盘导致既有盘(环境总览 / 四领域盘)渲染异常或链接失效;③ 抓取目标 up 数 < 14。

11. 第四阶段:覆盖缺口补齐 + Kibana 侧业务服务归并(2026-10-02)

11.1 背景与目标

第三阶段人工 UI 复验通过后,用户指出两处遗留,本阶段补齐:

  1. 覆盖缺口:宿主 192.168.31.250(job external-node-exporter,单数)与 4 台 K8s 节点 (job node-exporter)的指标没有 hostname 标签,统一入口盘覆盖不到它们;
  2. Kibana 侧仍是进程粒度:service.name 取值是 systemd/sshd/slurmctld,业务服务归并 此前只落在 Grafana 与服务目录,日志侧看不到「GitLab」「Slurm 调度」这样的业务视角。

完成状态:① 19 台主机(14 集群外 + 4 K8s 节点 + 1 宿主)指标均带 hostname; ② Kibana 分域视图出现「业务服务」控件与面板,历史 14 天数据同样生效。

11.2 关键技术结论(先读)

  • prometheus_deploy/values.yaml 已不是现场基线:2026-10-02 实测,现场 values (helm get values)比该文件多 10 项 —— Alertmanager 的 SMTP/route/inhibit_rules (由 dell-r620-monitor 与 env-monitor-deploy 两个工程叠加)与 grafana.nodeSelector: k8s-node-03。 按该工程 RUNBOOK §5.2 的 -f values.yaml 单文件升级会丢掉这 10 项(邮件路由失效、 Grafana 节点漂移)→ 本阶段改走 --reuse-values -f <overlay>(helm map 深合并、list 整体替换)。 (2026-10-03 更新)该缺口已闭环:漂移实际已涨到 13 项(本阶段的节点 relabel 与组三 #12 的 grafana 内存同样只走 overlay),已全部回写进 values.yaml(SMTP 授权码除外,凭据不入库), 见 prometheus-baseline-align-20261003/docs/SOP.md;此后单文件升级安全。
  • 对象级预演是唯一可信判据:helm upgrade --dry-run 的输出与 helm get manifest 逐对象哈希比对。 本次差异 = 1 个目标对象(node-exporter ServiceMonitor)+ 已知 hook 噪音(admission Job/ClusterRole)
  • Grafana PVC 的 spec.volumeName(服务端绑定字段,非漂移)。注意 helm 输出头尾都有非 YAML 内容 (header 与 NOTES),直接 yaml.safe_load_all 会解析失败,需按 # Source: / \n--- 裁切。
  • Alertmanager 运行配置的取证路径:operator 生成的是 alertmanager-<release>-alertmanager-generated,键名是 alertmanager.yaml.gz(gzip), 不是 alertmanager.yaml(后者是用户提供的源配置)。用计数而非打印正文(内含 SMTP 授权码)。
  • Kibana 侧业务服务用 runtime field 实现:写在 index-pattern saved object 的 attributes.runtimeFieldMap(字符串化 JSON,kibana_views.py 的字段子集比对会覆盖它)。 相比「Filebeat 写入新字段」:对历史数据立即生效、不改采集链、不重启;代价是查询时计算 (实测 24h 全量聚合约 4~6 秒)。
  • kubernetes.node.name 在 K8s 侧有值(k8s-master-01、k8s-node-01~03),而 host.name 是 Filebeat Pod 名 —— 故主机面板的 Kibana 跳链改用 kuery:host.name:X or kubernetes.node.name:X, 一条链接同时命中集群外主机与 K8s 节点。
  • 归并脚本首版留下 12% 「未归类」:K8s 节点的系统日志有 service.name 但既无 kubernetes.namespace 也无 cluster(它们是节点级 journal/文件日志,不带 Pod 元数据)。 加兜底(两者皆空 → 「K8s 集群与节点」)后归零。

11.3 分步操作(变更点)

# 变更点 文件 下发
1 data view 加 business_service runtime field(Painless,按 ns/cluster/service.name 归并 15 类) monitoring-p2-20261001/kibana/saved_objects/01-data-view.json main.py kibana
2 新增「日志量 · 按业务服务」Lens 面板 同目录 14-viz-business-service.json(新增) 同上
3 分域视图加「业务服务」控件 ctrl-biz + p12 面板 同目录 06-dashboard-domain-overview.json 同上
4 4 台 K8s 节点补 hostname/cluster log-metrics-crosslink-20261002/prom-node-exporter-relabel-overlay.yaml(新增 overlay) --reuse-values -f <overlay>(见下)
5 宿主补 hostname/cluster dell-r620-monitor-20260929/manifests/01-external-node-exporter.yaml kubectl apply -f 该文件(不要跑该工程完整 deploy,它会 helm upgrade 注入自己的 Alertmanager 路由)
6 新盘扩到 19 台 env-monitor-deploy/dashboards/service-map.yaml(svc 加 2 项、job 过滤放宽、跳链改 kuery)+ service-catalog.yaml 的 hosts_filter build-dashboards → deploy
cd /home/rain/Documents/k8s_ins
# 1) Kibana 侧(幂等,先 dry-run)
cd monitoring-p2-20261001 && .venv/bin/python main.py kibana --dry-run && .venv/bin/python main.py kibana
# 2) K8s 节点 relabel(**不许用 -f values.yaml 单文件**)
cd .. && helm upgrade --install kube-prometheus-stack prometheus_deploy/charts/kube-prometheus-stack-91.4.1.tgz \
  -n monitoring --reuse-values -f log-metrics-crosslink-20261002/prom-node-exporter-relabel-overlay.yaml \
  --no-hooks --timeout 30m --wait
# 3) 宿主 relabel
kubectl apply -f dell-r620-monitor-20260929/manifests/01-external-node-exporter.yaml
# 4) 新盘
cd env-monitor-deploy && .venv/bin/python main.py build-dashboards && .venv/bin/python main.py deploy

11.4 验证(2026-10-02 实测)

# 标签覆盖:三类 job 全部带 hostname(4+1+14)
kubectl -n monitoring exec prometheus-kube-prometheus-stack-prometheus-0 -c prometheus -- \
  promtool query instant http://localhost:9090 'count by (hostname,cluster)(up{job="node-exporter"})'        # 4 台,cluster=k8s
kubectl -n monitoring exec prometheus-kube-prometheus-stack-prometheus-0 -c prometheus -- \
  promtool query instant http://localhost:9090 'count by (hostname,cluster)(up{job="external-node-exporter"})'  # dell-r620 / dell_r620
# 两侧幂等
#   main.py kibana 复跑:全部 done、零变更;main.py deploy 复跑:变更执行 0 次

⚠ relabel 生效有延迟:ServiceMonitor 改动后需等 operator 重建抓取配置 + 一个抓取周期 (实测 K8s 节点约 45 秒、宿主约 90 秒才在 Prometheus 里看到新标签),验证时不要立即判定失败。

UI 复验(人工):Kibana 分域视图 →「业务服务」控件可选 15 类;「日志量 · 按业务服务」面板出数 (切换后明细表按业务服务过滤);Grafana env-service-map 的「业务服务」变量可选 7 项, 选「K8s 集群与节点」应出 4 台节点。

结案(2026-10-02):以上 UI 复验已由用户确认通过,第四阶段验收闭环; 「日志 ↔ 指标互跳」四阶段整体结案(无遗留动作)。

11.5 回滚

回滚对象 备份位置 回滚动作
01-data-view.json / 06-*.json backup/monitoring-p2-20261001/kibana/saved_objects/*.bak.20261002-135302 覆盖后 main.py kibana
K8s 节点 relabel backup/prometheus_deploy/manifests/pre-upgrade-20261002-135634.yaml(现场 manifest) helm rollback kube-prometheus-stack 10 -n monitoring(或反向 upgrade 去掉 overlay 中的 relabelings)
宿主 ServiceMonitor backup/dell-r620-monitor-20260929/manifests/01-external-node-exporter.yaml.bak.20261002-135302 覆盖后 kubectl apply -f 该文件
新盘与目录 backup/env-monitor-deploy/dashboards/service-map.yaml.bak.*、backup/log-metrics-crosslink-20261002/service-catalog.yaml.bak.* 覆盖后 build-dashboards + deploy

回滚触发判据(任一成立即回滚):① main.py kibana / deploy 返回非 0 或复检不过; ② Alertmanager 运行时配置丢失 email-p1/p2 或 smtp(api/v2/status 计数为 0); ③ Grafana nodeSelector 不再是 k8s-node-03;④ 抓取目标 up 数下降。

附录 A:交付物清单

文件 说明
SOP.md 本文件(含第一阶段与第二阶段)
backup/README.md + backup/ 修订前备份与台账
service-catalog.yaml 服务目录映射表(cluster / service.name → 指标侧大盘)
build-vega-panel.py Kibana Vega 面板声明文件生成脚本(避免双层转义)
(工程内)env-monitor-deploy/modules/k8s_ingest.py、manifests/01-*.tpl、dashboards/overview.yaml 指标标签与大盘 links / data link
(工程内)monitoring-p2-20261001/kibana/saved_objects/12-*.json、13-*.json、06-*.json Kibana 静态入口与 Vega 动态面板、仪表板挂载
env-monitor-deploy/dashboards/service-map.yaml(+ 生成物 manifests/15-env-service-map-dashboard.yaml) 第三阶段:统一入口盘精简源与生成物(uid env-service-map)
(工程内)env-monitor-deploy/config/env-monitor.yaml、dashboards/overview.yaml 第三阶段:新盘注册与环境总览入口 link
monitoring-p2-20261001/kibana/saved_objects/14-viz-business-service.json 第四阶段:按业务服务聚合的 Lens 面板(依赖 data view 的 business_service runtime field)
prom-node-exporter-relabel-overlay.yaml 第四阶段:4 台 K8s 节点 node-exporter 的 relabel overlay(必须与现场 values 合并,不许单文件升级)

附录 B:遗留(截至第四阶段)

  • 服务维度:日志侧已在第四阶段用 Kibana runtime field business_service 归并(15 类); 指标侧仍无 service.name 对应字段,「服务 → 指标」是间接映射(集群外按 hostname 正则、 K8s 平台服务按 kubernetes.namespace),不是精确字段对齐。
  • 覆盖缺口已补齐(第四阶段):19 台(14 集群外 + 4 K8s 节点 + 1 宿主)指标均带 hostname。 ⚠ 新增主机或节点时必须同步补 relabel(集群外走 env-monitor-deploy 的 nodes 配置、 K8s 节点走 prom-node-exporter-relabel-overlay.yaml、宿主走 dell-r620 的 ServiceMonitor), 否则新盘主机面板与服务维度会漏掉它。
  • prometheus_deploy/values.yaml 与现场 values 存在 10 项漂移(Alertmanager 路由/抑制规则、 Grafana nodeSelector),故升级必须 --reuse-values -f overlay;该文件何时重新对齐现场、 或改为 overlay 汇总属【待决策】。
  • 新盘 4 组面板与变量级联的渲染已由用户人工复验通过(2026-10-02,第三阶段); 第四阶段新增的「业务服务」控件 / p12 面板、扩到 19 台的主机面板亦已确认通过 (2026-10-02,见 11.4);互跳四阶段全部验收闭环,本主题已结案。
  • Kibana 原生 drilldown 在 8.19 无公开 API、无法声明式下发;若后续版本开放 /api/dashboards, 可考虑改回原生 URL drilldown 以换取更好的交互体验。
  • 服务目录映射表已建立,但指标侧没有 service.name 对应字段,故未实现 「服务 → 具体指标 job/role」的精确映射。

来源:/home/rain/Documents/k8s_ins/log-metrics-crosslink-20261002/SOP.md | 最后更新:2026-10-03 01:03(由 build/sync.py 同步,请勿在站点侧修改)