跳转至

INCIDENT-20260930 — 监控栈全栈重建(helm 漏传基线 values)

1. 概要

项 内容
时间 2026-09-29 23:58 – 2026-09-30 00:38(约 40 分钟,其中 Prometheus 不可用约 30 分钟)
等级 P1(可观测性中断;被监控业务未受影响)
影响面 monitoring 命名空间全栈:Prometheus / Alertmanager / Grafana / kube-state-metrics / operator / node-exporter DaemonSet 全部滚动重建
当前状态 已恢复:14/14 抓取目标 up、verify 与幂等复跑均通过、Alertmanager 两级邮件路由生效、两套大盘已导入
发现方式 执行本工程 deploy 时其自身校验报「抓取目标不足 仅 0/14 台 up」,随即人工核查发现 Pod 大面积重建

2. 影响范围

  • 业务:无影响。被监控的 Slurm/Lustre/LSF/HCL/FlexLM 主机与 K8s 业务 Pod 均未受影响。
  • 监控:Prometheus 中断采集约 30 分钟(存在不可补的指标缺口);Grafana / Alertmanager 短时不可用。
  • 数据:
  • Grafana PVC 被 Helm 删除(chart 默认 persistence.enabled=false)。删除前已将 NFS 上 53 MB 数据目录完整备份,并在新 PVC 上回填,面板与数据已恢复(见第 6 节验证)。Grafana 内部非面板状态(用户偏好、API Key 等)需人工抽查确认。
  • Prometheus / Alertmanager 的 PVC 未受影响(名与规格未变)。
  • 凭据:诊断过程中执行过一次 helm get values,其输出(含 SMTP 授权码明文)被打印到终端与会话上下文。该值原本就存在于集群 Secret 与本机 ~/.secrets/ 中,未外传;处置见行动项 A2。

3. 时间线

时刻 事件
23:58:15 执行 deploy 的集群侧阶段;实现体执行 helm upgrade(只传 Alertmanager overlay),helm revision 5 记为 deployed
23:58~00:00 chart 其余配置全部回落到默认值 → 全栈 Pod 重建;Prometheus 镜像被换成节点上未缓存的 v3.14.0-distroless,容器卡在拉镜像
00:00 前后 实现体校验报「抓取目标不足 仅 0/14 台 up」;人工核查发现 Prometheus PodInitializing 已 7 分钟、Grafana Init:0/1
00:07 确认 Grafana PVC 处于 Terminating(被 Helm 删除);导出 revision 4 的 values 作恢复基线(600)
00:07:46 备份 NFS 上 Grafana 数据目录(/srv/nfs/k8s/pvc-5ca538f8-….bak.20260930-000746,53 MB)
00:08 首次尝试 helm rollback 失败:no PersistentVolumeClaim with the name "kube-prometheus-stack-grafana" found
00:09 缩容 Grafana Deployment 释放该 PVC,PVC 随之删除
00:08~00:12 改用 helm upgrade -f <revision 4 values> 恢复整栈(rc=0);Grafana 新 PVC 建立并回填数据
00:13 发现两个 CR(Prometheus / Alertmanager)未随 helm 更新,改用 kubectl apply --server-side --force-conflicts 强制对齐
00:19~00:33 Prometheus 旧 Pod 卡在 Terminating;清理 node-02 上孤儿 sandbox、重启 kubelet 均无效;Grafana 改钉 k8s-node-03 后立即恢复
00:30:19 修正实现体后重跑 deploy,主机侧补放行「K8s 节点 IP」来源,集群侧完成;14/14 目标 up
00:38 幂等复跑 deploy 零变更、verify 全通过 → 收尾

4. 根因

主因(实现体缺陷):modules/k8s_ingest.py 的 _helm_upgrade_alertmanager() 只传了本工程的 Alertmanager overlay:

helm upgrade kube-prometheus-stack <chart> -n monitoring -f <Alertmanager overlay>

缺少现场 values 作基线,导致 chart 其余配置全部回落到默认值。证据:

helm get manifest kube-prometheus-stack -n monitoring --revision 5 | grep -m1 'image: "quay.io/prometheus/prometheus'
#   image: "quay.io/prometheus/prometheus:v3.14.0-distroless"    ← 默认值

连带后果: 1. 所有工作负载的 Pod 模板变化 → 全栈滚动重建; 2. Prometheus 镜像变为节点未缓存的 v3.14.0-distroless,拉取缓慢 → 长时间 Pending; 3. Grafana persistence.enabled 由 true 回落为 chart 默认 false → Helm 判定 PVC 不再需要并删除。

次生因素: 1. kubectl exec -c prometheus 的容器名写死,使校验把「查不到」误判为「一台都没抓到」,延误判断(实际容器名确为 prometheus,但 Pod 处于初始化时 exec 失败); 2. 抓取来源最初按 Calico IPPool(10.244.0.0/16)放行,而 Calico natOutgoing 会把 Pod 出集群流量 SNAT 成节点 IP,导致 11 台启用 firewalld 的主机抓取失败(该问题在本次一并修正); 3. 恢复阶段 helm rollback 被「正在 Terminating 的 PVC」挡住; 4. node-02 上引用新建 NFS PVC 的 Pod 卡在 Init:0/1(kubelet 停在 VerifyControllerAttachedVolume),重启 kubelet、清理孤儿 sandbox 均无效,换节点即恢复(根因未定位)。

5. 处置过程

  1. 止损优先级:先让 Prometheus 起来(停止拉取 v3.14.0),再处理 Grafana。
  2. helm rollback 失败 → 转为「用 helm get values --revision 4 导出的 values 重新 helm upgrade」,一次性恢复整栈配置。
  3. Grafana PVC 已进入 Terminating(不可撤销)→ 缩容 Deployment 让其完成删除,随后用新 PVC + 回填数据恢复。
  4. 两个 CR 未随 helm 更新 → 从 revision 7 manifest 中抽出 Prometheus / Alertmanager 两个 CR,用 --server-side --force-conflicts 强制对齐。
  5. 强制删除卡死的 Pod 对象(节点上已无对应容器);清理 node-02 上的孤儿 sandbox;Grafana 以 manifests/06-grafana-node-pin.yaml 钉到 k8s-node-03。
  6. 修正实现体 4 处缺陷后重跑 deploy 完成本次变更,并做幂等复跑。

6. 恢复验证

项 命令 结果
抓取目标 count by (cluster) (up{cluster=~"..."} == 1) {slurm:5, lsf:5, lustre:2, hpc:1, license:1} 合计 14,down 0
组件 kubectl get pods -n monitoring 全部 Running(Prometheus 2/2、Alertmanager 2/2、Grafana 3/3 …)
Prometheus 规格 kubectl get prometheus … -o jsonpath 镜像 v3.13.3、retention=15d、SC nfs-csi-hdd(与变更前一致)
邮件路由 解压 alertmanager-kube-prometheus-stack-alertmanager-generated 的 alertmanager.yaml.gz receivers = null / env-monitor-email-p1 / env-monitor-email-p2,SMTP 段存在
大盘 Grafana sidecar 日志 已导入 env-monitor-overview.json 与 node-exporter-full-1860.json
自检 .venv/bin/python main.py verify 退出码 0(14/14 up、规则已下发、AM 配置已生效)
幂等 .venv/bin/python main.py deploy 退出码 0,主机侧 14/14 全跳过、集群侧全跳过

7. 复盘

有效的做法 - 有前置备份:Alertmanager live values 与 Grafana 数据目录都在动手前导出 → 恢复有据可依; - 止血动作最小可逆:先恢复 Prometheus、再处理 Grafana;每一步都有独立验证; - 事故期间未触碰被监控业务,也未动用不可逆操作(未手工删 PV、未强制删有数据的对象)。

拖慢恢复的做法 - 首轮定位绕了弯:先怀疑节点异常,多花约 10 分钟;实际根因是 helm 参数缺失,比对 revision 5 的 manifest 一次即可确认; - helm rollback 被 PVC 挡住后,未立即转向「用旧 values 重新 upgrade」这条更直接的路径; - 校验脚本把「查询失败」与「真的没抓到」混为一谈,延长了误判时间; - 备份落盘未脱敏:helm get values 明文写入交付物目录(后已修正为脱敏 + 600)。

8. 行动项

# 事项 责任人 期限 状态
A1 修实现体:helm upgrade 必须带现场 values 基线(否则回落默认值) Agent 立即 已完成(含 _helm_upgrade_alertmanager 前置校验:缺基线直接拒绝执行)
A2 评估是否轮换 163 SMTP 授权码(诊断中曾被打印到终端与会话上下文) 用户 建议 7 天内 待决
A3 备份落盘脱敏 + 600(smtp_auth_password → 占位符) Agent 立即 已完成
A4 校验取配置改用 operator 实际键名 alertmanager.yaml.gz 并解压 Agent 立即 已完成
A5 Prometheus 查询容器名动态获取;查询失败与「零目标」区分开 Agent 立即 已完成
A6 防火墙放行来源由 Pod 网段改为 K8s 节点 IP(Calico SNAT) Agent 立即 已完成
A7 定位 k8s-node-02「新建 NFS PVC 的 Pod 卡在 Init:0/1」的根因 Agent 2026-09-30 完成一轮 已调查·未复现(复现实验 11 秒通过、无脏状态残留;判为当时的临时状态)。结论、排除清单与预防建议见 node02-init-stuck-20260930/20260930-k8s-node-02-Pod卡Init故障报告.md;后续靠 P1 补检测兜住
A8 恢复后清理:确认 Grafana 内部状态(用户/偏好/API Key)完好,并删除 NFS 上的数据备份目录 用户 确认无误后 待办
A9 把「helm upgrade 必须带基线 values」写入 RUNBOOK 与 SOP 的硬约束清单 Agent 立即 已完成

来源:/home/rain/Documents/k8s_ins/env-monitor-deploy/docs/INCIDENT-20260930-monitoring-fullstack-rollout.md | 最后更新:2026-09-30 01:25(由 build/sync.py 同步,请勿在站点侧修改)