SOP —— Kibana 日志分域视图¶
变更日期:2026-10-01 | 工程:
monitoring-p2-20261001| 类型:功能新增(C 类) 关联:docs/RUNBOOK.md§4.5(日常使用)、backup/kibana-domain-view-20261001/README.md(备份与回滚台账)
一、背景¶
EFK(ES + Kibana + Filebeat)已上线并稳定采集 4 个 K8s 节点与集群外 14 台主机, 但 Kibana 侧只有裸的 Discover,没有任何 data view、没有 dashboard——日志停留在 "能搜到"这一层,无法按集群域快速切分,也看不出各域日志的构成与量级。
实测确认的可聚合维度(全部为 keyword 字段):
| 字段 | 取值 | 覆盖范围 |
|---|---|---|
cluster |
slurm / lsf / lustre / hpc / license | 集群外 14 台全量(6 类采集全部打标) |
log_source |
syslog / audit / cron / domain / flexlm / vnc | 同上 |
kubernetes.namespace |
各命名空间 | K8s 容器日志(cluster 为空,占总量最大) |
二、目标¶
Kibana 中提供一个「日志分域视图」Dashboard,可按集群域与日志类别下钻, 并覆盖 K8s 容器的命名空间分布与原始日志明细;全部对象以声明式文件管理,可幂等重放。
三、前置条件¶
- Kibana 8.19.0 就绪,
kubectl -n monitoring exec elasticsearch-0 -- curl -s http://kibana:5601/api/status返回 200 - ES 中已存在
filebeat-*索引(两族:.ds-filebeat-*集群内 /.ds-filebeat-host-*集群外) ~/Documents/k8s_ins/monitoring-p2-20261001/.venv可用,config/default.yaml中 kubeconfig 路径有效
四、影响范围¶
| 项 | 说明 |
|---|---|
| 目标 | 仅 Kibana saved objects(monitoring 命名空间内的 Kibana 实例) |
| 是否停服 | 否。纯新增对象,不改 ES / Filebeat / Traefik,采集与检索不受影响 |
| 数据面 | 不触碰索引与 ILM;cluster 字段口径未做任何变更 |
| 回滚 | 删除新建的 6 个 saved object 即可,见第七章 |
五、分步操作¶
步骤 1:下发声明式 saved objects¶
声明源位于 kibana/saved_objects/*.json(一个文件 = 一个 saved object):
| 文件 | 类型 | id | 作用 |
|---|---|---|---|
01-data-view.json |
index-pattern | efk-all-logs |
数据视图 filebeat-*,时间字段 @timestamp |
02-viz-cluster-count.json |
lens | efk-viz-cluster-count |
按集群域统计日志量 |
03-viz-cluster-source.json |
lens | efk-viz-cluster-source |
域 × 日志类别堆叠 |
04-viz-namespace-count.json |
lens | efk-viz-namespace-count |
K8s 命名空间分布(query: kubernetes.namespace: *) |
05-search-recent-logs.json |
search | efk-search-recent-logs |
原始日志明细 |
06-dashboard-domain-overview.json |
dashboard | efk-dashboard-domain-overview |
组合视图(9 面板)+ 6 个 Options list 控件;默认时间窗 now-24h |
07-viz-level-trend.json |
lens | efk-viz-level-trend |
日志级别趋势(后续追加) |
08-viz-error-by-host.json |
lens | efk-viz-error-by-host |
异常来源 · 按主机(后续追加) |
09-viz-error-by-pod.json |
lens | efk-viz-error-by-pod |
异常来源 · 按 K8s Pod(后续追加) |
10-viz-service-count.json |
lens | efk-viz-service-count |
日志量 · 按服务(2026-10-02 追加,见步骤 4) |
11-viz-service-level.json |
lens | efk-viz-service-level |
日志构成 · 服务 × 级别(2026-10-02 追加,见步骤 4) |
下发通道:Kibana 未对集群外暴露 REST,统一经 ES Pod 内的 curl 访问集群内 kibana:5601。
等价的底层命令(以「写入单个对象」为例,实际由实现体批量下发):
kubectl --kubeconfig /home/rain/.kube/config -n monitoring exec -i elasticsearch-0 -- \
bash -lc 'E="elastic:$ELASTIC_PASSWORD"; \
curl -s -u "$E" -H "kbn-xsrf: true" -H "Content-Type: application/json" \
-X POST "http://kibana:5601/api/saved_objects/_bulk_create?overwrite=true" \
--data-binary @-' < <(python3 -c 'import json,sys;print(json.dumps([json.load(open("kibana/saved_objects/02-viz-cluster-count.json"))]))')
预期:返回 {"saved_objects":[...]},无 errors 字段。
失败判断:非 200 或出现 errors → 检查 body 的 JSON 合法性(Kibana 不校验 attributes,畸形数据会静默写入)。
实现体:modules/kibana_views.py(KibanaViews.apply)。
步骤 2:dashboard 的面板组装(本步是本次唯一的坑)¶
dashboard 的面板不手写内联,而是在 06-*.json 里声明:
"panels": [
{"panel": "p1", "ref": "efk-viz-cluster-count", "x": 0, "y": 0, "w": 24, "h": 15, "title": "日志量 · 按集群域"}
]
modules/kibana_views.py::_expand 会读入被引用对象的 attributes,按 Kibana 8.x
by-reference 面板格式生成 panelsJSON 与 references:
[{"type":"lens",
"embeddableConfig":{"savedObjectId":"efk-viz-cluster-count","title":"日志量 · 按集群域"},
"panelIndex":"p1",
"gridData":{"x":0,"y":0,"w":24,"h":15,"i":"p1"}}]
注意事项与坑(务必留痕):
savedObjectId必须放在embeddableConfig内,不能放面板顶层。 放在顶层时 Kibana 不报错,但面板渲染为空并抛出Cannot read properties of undefined (reading 'map')——极难定位。references.name必须等于该面板的panelIndex(如p1),不是panel_p1。- 本格式取自 Kibana Dashboards API 的实测产物(
PUT/POST /api/dashboards/dashboard[/{id}]), 而非文档推断:先用该 API 创建一枚探针 dashboard,再GET /api/saved_objects/dashboard/<id>读回它生成的panelsJSON,即得标准形态。 - dashboard 的
references由_expand一并生成,声明文件里写"references": []即可。 index-pattern的fields会被 Kibana 回写,比对时已在IGNORED_ATTRS中跳过, 否则每次 apply 都会误判为漂移。
步骤 3:执行下发(幂等)¶
cd /home/rain/Documents/k8s_ins/monitoring-p2-20261001
.venv/bin/python main.py kibana --dry-run # 只列差异,零副作用
.venv/bin/python main.py kibana # 真实下发
预期(首次建立):除 index-pattern 外全部 pending → 已写入 N 个对象 → 复检通过。
预期(复跑):全部 done → 全部对象已与声明一致,无变更(幂等跳过)。
实现体:main.py 子命令 kibana → deployer.py::cmd_kibana。
步骤 4:服务维度可视化补齐(2026-10-02,两轮)¶
背景:服务维度(service.name)此前只落地为「筛选控件 + 明细表一列」,没有任何按服务分组的图表,界面上看不出效果。第一轮补一枚「日志量 · 按服务」面板;上线后用户反馈「只有一根柱、且界面看不到服务控件」,据此做第二轮:收时间窗、改控件级联、补「服务 × 级别」面板。只改声明文件,不动采集链路。
做法(两轮,均只改声明文件,不动采集链路):
第一轮(补 p8「日志量 · 按服务」):
- 新建
kibana/saved_objects/10-viz-service-count.json——照抄02-viz-cluster-count.json的结构(已在 Kibana 实测渲染通过),只改id/title、sourceField: cluster → service.name、query设为service.name: *(滤掉空值,避免空桶占位)。 - 在
06-*.json的panels声明里挂载p8,明细面板p6由y=36下移到y=48。
第二轮(上线后发现「界面只有一根柱、且「服务」控件不渲染」,据此修可见性与信息量):
- 新建
kibana/saved_objects/11-viz-service-level.json——照抄03-viz-cluster-source.json的双维度堆叠结构(splitAccessors),cluster → service.name、log_source → log.level;挂载为p9,p6再下移到y=60。 06-*.json另改两处:timeFrom: now-7d → now-24h——服务维度只对上线后新采日志有值,7 天窗口覆盖率仅 3.9%,面板与控件近乎空白;controlGroupInput.chainingSystem: HIERARCHICAL → NONE——级联模式下「服务」控件在界面不渲染(详见坑 3),改独立筛选后 6 个控件恒显。⚠ 第四轮已改回HIERARCHICAL(关级联会让"选主机后仍列全部服务")。
{"panel": "p9", "ref": "efk-viz-service-level", "x": 0, "y": 48, "w": 48, "h": 12, "title": "日志构成 · 服务 × 级别"}
第三轮(让下钻同屏可见):p8 / p9 改为并排(各 24 宽、同一行 y=36),「最近日志明细」上移到该行正下方(y=48、48×16)并改标题为「最近日志明细(点上方服务柱 → 只看该服务的日志)」——此前明细表在最底部,点服务柱后联动结果看不到,"点服务看日志"的体验无法感知。
第四轮(恢复级联):chainingSystem 由 NONE 改回 HIERARCHICAL。触发:用户选中主机后「服务」控件仍列出全部 54 个服务(含 K8s 侧服务)——根因即第二轮为修控件显示而关掉的级联。改后重放 main.py kibana,幂等通过。本轮未做浏览器复验(无头浏览器卡在 /internal/data_views/fields 请求上),需人工确认两点:① 6 个控件仍全部显示;② 选中主机后「服务」只列该主机出现过的服务。
注意事项与坑:
seriesType不要自创:沿用已验证的bar_stacked;双维度堆叠用splitAccessors(参照03-*.json),不是加第二层 x 轴。Kibana 不校验 saved object 结构,格式写错会静默入库、只在浏览器里渲染为空(见步骤 2 坑 1)。- 数据口径:面板只反映「时间窗内
service.name非空」的文档;实测 24h 内 8.2 万条中 48% 的log.level为空(auditd / openldap / traefik 等主机侧日志),故「服务 × 级别」图例会带一段(空),属正常而非故障。 - 「服务」控件的级联取舍(第二轮 ⇄ 第四轮的往返,务必看):Kibana 侧对象里
ctrl-service始终存在(GET /api/saved_objects/dashboard/<id>可查,panelsJSON含 6 个控件),但界面只渲染 5 个。第二轮据此把chainingSystem由HIERARCHICAL改成NONE,控件随即显示——代价是丢掉级联:选中主机后「服务」仍列出全部 54 个服务(含 K8s 侧服务),第四轮已改回HIERARCHICAL。 - 教训:不要把「某控件不显示」直接归因为级联——当时并未排除浏览器缓存、上游控件空值等其它可能,也没做硬刷新复判就改了配置,代价是用户看到"选主机还列全部服务"。
- 回退姿势:级联开关就是一个字段,声明里改一行 +
main.py kibana重放即可(第四轮即如此)。 - 改完控件配置必须硬刷新(关键):Kibana 的 dashboard 只在页面加载时读取 saved object;下发后若只是点「Refresh」(刷新数据),前端仍在用旧配置——用户两次误判"级联没生效"均源于此。实测(2026-10-02,浏览器实机):硬刷新后选中
slurm-master-01,「服务」由 54 options 收敛为 11 options(auditd 2,698 / systemd 1,596 / systemd-logind 71 / user@0 56 / sshd 48 …),与 ES 直接聚合一致。
cd /home/rain/Documents/k8s_ins/monitoring-p2-20261001
PYTHONPATH="$HOME/py_public_modules" .venv/bin/python main.py kibana --dry-run # 预期:2 个 pending,其余 done
PYTHONPATH="$HOME/py_public_modules" .venv/bin/python main.py kibana # 真实下发
预期:已写入 2 个对象 → 复检通过;复跑一次全部 done(幂等)。
失败判断:写入后复检未通过 → 检查声明 JSON 是否畸形(Kibana 不回显结构错误,看渲染需人工)。
实现体:modules/kibana_views.py::_expand;备份与局部回滚台账 backup/service-panel-20261002/README.md。
步骤 5:Discover 服务浏览入口(2026-10-02,HANDOFF 组三 #11)¶
背景:分域视图只能在看板内点选,缺一条「进 Discover 自由按服务/主机检索」的路径;而 Kibana 8.19 未开放 drilldown 的声明式 API(见 §9 结论),原生下钻无法下发。故补「保存的搜索 + 入口链接」作为替代,只新增对象、不动采集链路。
做法:
- 新建
kibana/saved_objects/16-search-service-browse.json:typesearch、idefk-search-service-browse,kueryservice.name: *,列service.name / host.name / log.level / log_source / message,按@timestamp倒序。 - 新建
kibana/saved_objects/15-markdown-discover-links.json:typevisualization、markdown 面板,两条链接——打开上述保存搜索 / 在 Discover 打开全部日志(index:'efk-all-logs')。 06-dashboard-domain-overview.json的panels追加p13(该 markdown,y=96 w=48 h=8)。
cd /home/rain/Documents/k8s_ins/monitoring-p2-20261001
PYTHONPATH="$HOME/py_public_modules" .venv/bin/python main.py kibana --dry-run # 预期:3 个 pending(dashboard + 2 个新建)
PYTHONPATH="$HOME/py_public_modules" .venv/bin/python main.py kibana # 预期:已写入 3 个对象 → 复检通过
PYTHONPATH="$HOME/py_public_modules" .venv/bin/python main.py kibana # 复跑:无变更(幂等跳过)
预期:已写入 3 个对象 → 复检通过:3 个对象均已与声明一致;复跑 无变更(幂等跳过)。
失败判断:复检不通过 → 检查两个新 JSON 是否畸形(Kibana 不校验结构,畸形会静默入库、渲染为空);
回滚见第 7 章与 backup/kibana-discover-20261002/README.md。
实现体:modules/kibana_views.py(_expand 把 dashboard 的 panels 声明展开为 panelsJSON + references)。
注意事项与坑:
- markdown 链接含
()'等字符,必须用<URL>尖括号包裹,否则 markdown 解析会截断链接。 - 保存搜索的 id(
efk-search-service-browse)与 markdown 链接路径必须一致,改名要同步两处。 - ⚠ Discover 打开保存搜索的 URL 形式(
#/view/<id>)未做浏览器实测(无头浏览器不可用); 若点开未落在该搜索上,改走「Discover → 选 data viewefk-all-logs」路径。
六、验证¶
- 幂等:连续执行两次,第二次零变更(见步骤 3 预期)。
- 对象齐备:
bash kubectl -n monitoring exec elasticsearch-0 -- bash -lc 'E="elastic:$ELASTIC_PASSWORD"; \ curl -s -u "$E" "http://kibana:5601/api/saved_objects/_find?type=dashboard&per_page=10" | head -c 300'预期:total≥ 1,包含efk-dashboard-domain-overview。 - 渲染(人工):浏览器打开
https://kibana.rainchen.top/app/dashboards#/view/efk-dashboard-domain-overview预期:顶部 7 个控件(主机 / K8s Pod / 服务 / 级别 / 集群域 / 类别 / 业务服务,均应可见)+ 13 个面板全部有内容 (含「日志量 · 按服务」与「日志构成 · 服务 × 级别」;默认时间窗 24h 即有画面,收到最近 1 小时最清晰), 无Cannot read properties of undefined报错。 - 漂移检测并入只读命令:
bash .venv/bin/python main.py drift # 退出码 0=无漂移 / 1=有漂移 / 2=探测失败
七、回滚¶
删除本次新建的 11 个对象即可,ES 数据与采集链路不受影响:
kubectl -n monitoring exec elasticsearch-0 -- bash -lc 'E="elastic:$ELASTIC_PASSWORD";
for t in lens:efk-viz-cluster-count lens:efk-viz-cluster-source lens:efk-viz-namespace-count \
lens:efk-viz-level-trend lens:efk-viz-error-by-host lens:efk-viz-error-by-pod \
lens:efk-viz-service-count lens:efk-viz-service-level search:efk-search-recent-logs \
dashboard:efk-dashboard-domain-overview index-pattern:efk-all-logs \
visualization:efk-markdown-discover-links search:efk-search-service-browse; do
curl -s -o /dev/null -w "$t %{http_code}\n" -u "$E" -H "kbn-xsrf: true" \
-X DELETE "http://kibana:5601/api/saved_objects/${t%%:*}/${t##*:}"
done'
预期:每行 200。随后删除 kibana/ 目录并把 main.py / deployer.py 回退到改动前状态
(改动清单与手工回退步骤见 backup/kibana-domain-view-20261001/README.md)。
仅撤销 2026-10-02 新增的「日志量 · 按服务」面板(局部回滚,不影响其余 7 个面板):
cd /home/rain/Documents/k8s_ins/monitoring-p2-20261001
rm kibana/saved_objects/10-viz-service-count.json # 高危:删除文件,路径已明确
cp -p backup/service-panel-20261002/kibana/saved_objects/06-dashboard-domain-overview.json.bak.20261002-002221 \
kibana/saved_objects/06-dashboard-domain-overview.json # 高危:覆盖配置,原件已备份
PYTHONPATH="$HOME/py_public_modules" .venv/bin/python main.py kibana # dashboard 回到 7 面板
kubectl --kubeconfig /home/rain/.kube/config -n monitoring exec elasticsearch-0 -- \
bash -lc 'E="elastic:$ELASTIC_PASSWORD"; curl -s -u "$E" -H "kbn-xsrf: true" \
-X DELETE "http://kibana:5601/api/saved_objects/lens/efk-viz-service-count"'
详见 backup/service-panel-20261002/README.md。
八、风险说明¶
| 风险 | 缓解 |
|---|---|
| Kibana 不校验 saved object 结构,畸形数据静默写入 | 面板格式由 _expand 统一生成,不手写;渲染以浏览器实测为准 |
| Kibana 版本升级后 embeddable 格式变化 | 面板字段集中在 _expand 一处,升级后只需改这一处并复跑验证 |
时间窗默认 7 天(timeRestore: true)可能让人误判无数据——2026-10-02 实测:service.name 仅上线约 1h,7d 窗口覆盖 3.9%,「服务」控件近乎为空 |
Dashboard 描述里写明;时间选择器可随时改;排查「新字段无数据」时先把窗口收到 1 小时 |
控件依赖 dataViewId=efk-all-logs,改 data view id 会失效 |
两处同源声明,改 id 时一并改 |
附录:交付物清单¶
| 文件 | 说明 |
|---|---|
kibana/saved_objects/01..11-*.json |
声明式 saved objects(单一真源) |
modules/kibana_views.py |
幂等下发器(三态探测 + 子集比对 + 展开组装) |
main.py / deployer.py |
新增 kibana 子命令;drift 并入视图漂移检测 |
backup/kibana-domain-view-20261001/README.md |
备份与回滚台账(首次建立) |
backup/service-panel-20261002/README.md |
备份与回滚台账(2026-10-02 新增「日志量 · 按服务」面板) |
来源:
/home/rain/Documents/k8s_ins/monitoring-p2-20261001/docs/SOP-kibana-domain-view.md| 最后更新:2026-10-02 23:06(由build/sync.py同步,请勿在站点侧修改)