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