跳转至

RUNBOOK — 环境主机监控(env-monitor-deploy)

本文件回答「这个服务平时怎么用、怎么查、怎么救」,面向接手值班的人。 本次变更的过程与回滚见同目录 SOP.md;两者不重复写同一件事。

目录

  1. 服务概览
  2. 接入与凭据
  3. 日常速查表
  4. 日常操作
  5. 配置管理
  6. 备份与恢复
  7. 监控与告警
  8. 故障处置
  9. 安全与权限
  10. 容量与性能
  11. 附录

1. 服务概览

干什么用的:把集群外的 14 台主机(Slurm / Lustre / LSF / HPC / FlexLM)的主机层 指标采集进本环境的 Prometheus,并提供统一大盘与邮件告警。

由哪些组件构成

组件 位置 作用
node-exporter(包)/prometheus-node-exporter.service(单元) 14 台目标主机,systemd 单元监听 :9100 暴露主机层指标
领域采集器 env-<领域>-metrics(Slurm / Lustre / LSF / FlexLM) 目标机 /usr/local/bin/ + /etc/systemd/system/env-<领域>-metrics.{service,timer} 每 60s 采一次领域指标,写 agent.textfile_dir 下的 <领域>.prom,由 node-exporter 的 textfile collector 顺带暴露(不新增端口)
systemd drop-in 目标机 /etc/systemd/system/prometheus-node-exporter.service.d/10-env-monitor.conf 固定采集器开关与端口
Service / Endpoints / ServiceMonitor monitoring 命名空间 external-node-exporters 静态接入 Prometheus 抓取
PrometheusRule monitoring/ 下 env-host-baseline-alerts、env-cluster-baseline-alerts、env-slurm-alerts、env-lsf-alerts、env-domain-alerts 主机基础告警 + 集群侧告警 + 领域告警(Slurm 与 LSF 各自成组;Lustre 与 FlexLM 合并为 env-domain-alerts)
ConfigMap(Grafana 大盘) monitoring/ 下 env-monitor-overview、env-slurm-dashboard、env-lustre-dashboard、env-lsf-dashboard、env-flexlm-dashboard、node-exporter-full-1860 环境总览 + 四个角色详情盘 + 社区单机盘(sidecar 自动导入)
Alertmanager 路由 monitoring 命名空间,helm release kube-prometheus-stack 主机告警分级邮件

依赖谁:kube-prometheus-stack(Prometheus / Alertmanager / Grafana / Operator); 目标机可达的 EPEL 仓库(仅装包时需要);操作机的 SSH 免密。

异常时的业务影响:

  • 采集中断 → 只是「看不见」,不影响被监控主机上的业务;
  • 目标机 node-exporter 是只读采集进程,不参与 Slurm/Lustre/LSF 的任何调度或数据路径;
  • 唯一的写操作是防火墙放行与 systemd 单元,回滚即恢复。

重要性等级:中(可观测性组件;失效不直接中断业务,但会导致故障不可见)。

2. 接入与凭据

项 值
目标机 SSH root@192.168.31.16 ~ .29(免密,仅操作机 192.168.31.249 可用)
指标端口 9100/tcp,仅对 10.244.0.0/16(Calico Pod 网段)放行
Prometheus 查询 kubectl --kubeconfig /home/rain/.kube/config exec -n monitoring <prom-pod> -c prometheus -- wget -qO- --post-data='query=<expr>' http://localhost:9090/api/v1/query
Grafana https://grafana.rainchen.top(管理员口令见下)
工程配置 config/env-monitor.yaml
日志 logs/env-monitor-deploy.log(按日切割,保留 30 天)
报告 reports/precheck-*.md、reports/drift-*.md

凭据存放与取用

用途 位置 取用方式
Grafana 管理员 ~/.secrets/prod.env 的 PROD_GRAFANA_ADMIN_USER / PROD_GRAFANA_ADMIN_PASSWORD set -a; . "$HOME/.secrets/prod.env"; set +a
Alertmanager SMTP 授权码 ~/.secrets/dell-r620-monitor.env 的 DELL_R620_SMTP_AUTH_PASSWORD 由实现体运行时读取,不要手工 cat

红线:~/.secrets/ 下文件权限 600,禁止 Read/cat 其内容, 只允许在命令内 source 或引用变量;非交互 shell 必须显式 source。

客户端接入示例(手工核对某台机器的原始指标):

timeout 10 curl -s http://192.168.31.16:9100/metrics | grep -E '^node_load1|^node_boot_time_seconds'

3. 日常速查表

cd /home/rain/Documents/k8s_ins/env-monitor-deploy

# 1. 链路体检(只读):抓取目标是否全 up
.venv/bin/python main.py verify

# 2. 漂移检测(只读):实机是否偏离期望态(0 无漂移 / 1 有漂移 / 2 检测失败)
.venv/bin/python main.py drift

# 3. 单台三要素快检(以 .16 为例)
ssh root@192.168.31.16 "systemctl is-active prometheus-node-exporter; systemctl is-enabled prometheus-node-exporter; ss -lntH | grep ':9100'"

# 4. 单台查看服务日志
ssh root@192.168.31.16 "journalctl -u prometheus-node-exporter -n 50 --no-pager"

# 5. 查看防火墙是否已放行
ssh root@192.168.31.16 "firewall-cmd --list-rich-rules | grep 9100"

# 6. Prometheus 里的目标状态
kubectl --kubeconfig /home/rain/.kube/config exec -n monitoring \
  $(kubectl --kubeconfig /home/rain/.kube/config get pods -n monitoring -l app.kubernetes.io/name=prometheus -o jsonpath='{.items[0].metadata.name}') \
  -c prometheus -- wget -qO- --post-data='query=up{job=~"external-node-exporters.*"} == 0' \
  http://localhost:9090/api/v1/query

# 7. 当前 firing 的主机告警
kubectl --kubeconfig /home/rain/.kube/config exec -n monitoring \
  $(kubectl --kubeconfig /home/rain/.kube/config get pods -n monitoring -l app.kubernetes.io/name=prometheus -o jsonpath='{.items[0].metadata.name}') \
  -c prometheus -- wget -qO- --post-data='query=ALERTS{alertstate=\"firing\", category=\"host\"}' \
  http://localhost:9090/api/v1/query

# 8. 重跑收敛(幂等;已达标主机会被跳过)
.venv/bin/python main.py deploy

# 9. 预检查(只读,含抓取来源推导)
.venv/bin/python main.py precheck

# 10. 忽略预检缓存,强制重跑预检
.venv/bin/python main.py deploy --refresh-precheck

关于预检与复用:deploy / verify / drift 都要先过预检(门禁)。预检结论缓存在 reports/.precheck-cache.json,默认 300 秒内复用;缓存指纹=配置+全部实现体源码 的 sha256,任一改动自动失效。一轮预检约 11 秒,命中缓存约 0.3 秒。 把 ops.precheck_cache_ttl_seconds 设为 0 可永久关闭复用。

4. 日常操作

状态检查(完整)

cd /home/rain/Documents/k8s_ins/env-monitor-deploy
.venv/bin/python main.py verify      # 期望:全部 14 台五要素通过

单台启停(高危:启停服务)

ssh root@192.168.31.16 "systemctl restart prometheus-node-exporter"     # 重启
ssh root@192.168.31.16 "systemctl stop prometheus-node-exporter"        # 停止(该台 target 会 down)
ssh root@192.168.31.16 "systemctl start prometheus-node-exporter"

停止后 Prometheus 会在 5 分钟后触发 EnvHostDown(critical)并发邮件。

新增一台主机:改 config/env-monitor.yaml 的 nodes 段加一行 → precheck → drift → deploy。新主机会被装包/放行,已有主机全部跳过。

移除一台主机:从 nodes 段删除 → precheck → deploy(清单会重渲染,该端点消失)→ 再手工 ssh root@<ip> "systemctl disable --now prometheus-node-exporter && dnf remove -y node-exporter"。

看日志

tail -n 100 logs/env-monitor-deploy.log                     # 实现体日志
ssh root@192.168.31.16 "journalctl -u prometheus-node-exporter --since '30 min ago'"

大盘与日志互跳(2026-10-02 新增)

5 个环境大盘(总览 / Slurm / Lustre / LSF / FlexLM)右上角均有「查看日志(Kibana)」链接, 跳转到 EFK 的日志分域视图。

  • 链接声明在精简源 dashboards/*.yaml 的顶层 extra.links,由生成器透传到大盘 JSON。 改链接请改精简源并重跑 python main.py build-dashboards,勿手改 manifests/ 产物。 ⚠ overview.yaml 原本已有顶层 extra(version),新增键必须合并进同一个 extra—— YAML 同名顶层键后写覆盖先写且不报错。
  • 为支撑互跳,14 台集群外主机的指标新增 hostname 标签(裸主机名,无端口), 与日志侧 host.name 同口径;由 modules/k8s_ingest.py 的 relabel 逐台生成。 验证:count(up{job="external-node-exporters", hostname!=""}) 应为 14。
  • 动态跳转(第二阶段,2026-10-02):总览大盘「CPU / 内存 / 根分区使用率 Top15」悬停柱形会出现 「查看该主机日志(Kibana)」,点击按该主机 host.name 打开 Kibana 分域视图。 data link 写在精简源对应面板的 fieldConfig.defaults.links,用 ${__field.labels.hostname} 取值; ⚠ 被聚合掉 hostname 的查询(如 CPU 面板原为 avg by (instance, cluster))须先补回该标签, 否则链接取不到值。
  • 详见 log-metrics-crosslink-20261002/SOP.md §9。

5. 配置管理

配置项位置:config/env-monitor.yaml(唯一真源,含全部注释)。关键段:

段 管什么
nodes 受管主机(键名=集群名→cluster 标签,name→instance,role→role 标签)
agent 包名、systemd 单元、drop-in 路径、collector 开关、端口
firewall 是否放行、源网段(auto = 由 Calico IPPool 推导)、端口
kubernetes kubeconfig、命名空间、release、本地 chart 包、清单模板、大盘制品
alertmanager 收件人、SMTP、抑制规则
ops 批次规模、并发、失败阈值、各类超时
precheck 期望 OS 主版本、磁盘/时钟阈值、可跳过的检查项

修改流程:改配置 → .venv/bin/python main.py precheck(先看结论)→ .venv/bin/python main.py deploy(幂等收敛)。

大盘(生成物):5 个环境大盘的唯一真源是 dashboards/*.yaml 精简源, manifests/ 里的大盘 YAML 由 main.py build-dashboards 生成,不得手改:

$EDITOR dashboards/<name>.yaml                     # 只写差异行(不写 id / gridPos / datasource / refId)
.venv/bin/python main.py build-dashboards          # 生成(幂等:内容未变则报「未变」)
.venv/bin/python main.py build-dashboards --check  # 只校验精简源与 manifests 是否一致,不写文件
.venv/bin/python main.py deploy                    # 下发

pre_check 会校验二者一致性,手改 manifests 会被 BLOCK。详见 docs/SOP.md 附录 G.9。

生效方式:

  • 主机侧参数(collector、端口)→ 写 drop-in 后 systemctl daemon-reload && restart;
  • 清单类(Endpoints/规则/大盘)→ kubectl apply;
  • Alertmanager → helm upgrade(必须带 --no-hooks,理由见第五节末尾)。

易错点

  • nodes 段改主机名会改变 instance 标签,历史看板与告警的 instance 引用会一起变; 且主机名必须是小写 RFC1123 label(它同时作为 Endpoints 的 hostname, 大写会被 K8s API 拒绝,实测 Flexlm 被拒);
  • firewall.sources 取 auto 时推导的是 K8s 节点 IP,不是 Pod 网段 (Calico natOutgoing 会把 Pod 出集群流量 SNAT 成节点 IP);
  • chart 包路径是相对工程根解析的,挪动 prometheus_deploy/charts/*.tgz 会破坏升级;
  • helm upgrade 必须带现场 values 作基线(-f <现场 values> -f <overlay>)。 只传本工程 overlay 会让其余配置回落到 chart 默认值,触发全栈重建 —— 本次实施已实际发生并造成 P1 事故,见 INCIDENT-20260930-monitoring-fullstack-rollout.md。实现体已加前置校验: 缺基线直接拒绝执行;
  • Alertmanager 运行配置在 Secret 里以 alertmanager.yaml.gz(gzip)存放, 不是 alertmanager.yaml;取配置时需按 gzip 解压。

6. 备份与恢复

备份策略:变更前自动备份,位置 env-monitor-deploy/backup/,台账 backup/README.md。

对象 备份位置
Alertmanager live values backup/cluster/kube-prometheus-stack-values.live.yaml.bak.<时间戳>
改前 Alertmanager 运行配置 backup/cluster/alertmanager-config.yaml.bak.<时间戳>
目标机 drop-in(若原本存在) 目标机原位 /etc/systemd/system/prometheus-node-exporter.service.d/10-env-monitor.conf.bak.<时间戳>

手工备份

cd /home/rain/Documents/k8s_ins/env-monitor-deploy
helm --kubeconfig /home/rain/.kube/config get values kube-prometheus-stack -n monitoring -o yaml \
  > backup/cluster/kube-prometheus-stack-values.live.yaml.bak.$(date +%Y%m%d-%H%M%S)
ssh root@192.168.31.16 "cp -a /etc/systemd/system/prometheus-node-exporter.service.d/10-env-monitor.conf \
  /etc/systemd/system/prometheus-node-exporter.service.d/10-env-monitor.conf.bak.$(date +%Y%m%d-%H%M%S)"

恢复:完整回滚步骤见 docs/SOP.md 第 7 章;单台 drop-in 恢复:

ssh root@192.168.31.16 "cp -a <备份文件> /etc/systemd/system/prometheus-node-exporter.service.d/10-env-monitor.conf && systemctl daemon-reload && systemctl restart prometheus-node-exporter"

恢复后验证:ss -lntH | grep ':9100' 有监听;.venv/bin/python main.py drift 退出码 0。

演练记录:截至本文成文,单台 drop-in 恢复路径尚未实战演练(首次变更前无备份可恢复); 下一次变更前建议在 .16 上演练一次。

7. 监控与告警

关键指标与查看入口

想确认 去哪 看什么
采集是否正常 Grafana →「环境总览」 「在线主机」= 19、「失联主机」= 0
主机资源水位 Grafana →「环境总览」→ 资源水位 CPU/内存/根分区 Top15,>85% 标红
单机全量 Grafana →「Node Exporter Full」 变量 node 选主机名(如 slurm-work-01)
Slurm 集群在干什么 Grafana →「Slurm 集群」 分区/节点 CPU 与内存、作业队列、控制端与调度器健康
Slurm 作业效率与卡点 Grafana →「Slurm 集群」 运行时长 vs 时限、时长分布、近 1h 完成/失败作业、CPU 效率(TotalCPU/CPUTime)
Slurm 是否卡在 License Grafana →「Slurm 集群」→ 跨域联动 运行作业数 vs FlexLM 许可占用、slurm_sched_blocked_on_licenses
谁在用集群(项目维度) Grafana →「Slurm 集群」→ 公平性与账户 Account 的 RawUsage 排行、NormShares 与 FairShare
Lustre 存储健康 Grafana →「Lustre 存储」→ 服务与采集健康 采集状态、客户端设备(mgc/lov/lmv/mdc/osc)、MDT/OST 挂载客户端数、驱逐趋势
Lustre 容量与水位 Grafana →「Lustre 存储」→ 容量与水位 客户端/OST/MDT 已用率、inode 使用率、grant 空间(含受阻 pending)
Lustre 元数据性能 Grafana →「Lustre 存储」→ 元数据性能(MDS) md_stats 操作速率与平均延迟、近 1h 操作分布
Lustre 数据 IO Grafana →「Lustre 存储」→ 数据 IO 性能(OSS) OST 操作速率与平均延迟、近 1h 操作分布
Lustre 磁盘层 IO Grafana →「Lustre 存储」→ 磁盘层 IO brw_stats 的 IO 大小/延迟/队列深度/块映射分布(空载时无数据,非故障)
Lustre 客户端体验 Grafana →「Lustre 存储」→ 客户端体验 llite 操作速率与端到端延迟、RPC 重传、客户端 grant 使用
Lustre 与作业联动 Grafana →「Lustre 存储」→ 跨域联动 存储用量 vs Slurm/LSF 作业数、客户端连接数 vs 许可占用
LSF 集群与调度器健康 Grafana →「LSF 调度」→ 集群与调度器健康 采集状态、集群/主控/mbatchd 状态、服务器状态、作业与用户、集群容量
LSF 队列积压与等待 Grafana →「LSF 调度」→ 队列压力与等待 各队列 PEND、Pending 原因 TopN、调度等待时延
LSF 调度器与 License 阻塞 Grafana →「LSF 调度」→ 调度器与 License 阻塞 估计队列与作业信息缓存、Pending 原因趋势、待调度资源需求
LSF 作业效率 Grafana →「LSF 调度」→ 作业运行与资源效率 运行时长分布、槽位/内存需求、近 1 小时吞吐与 Slot/Memory 利用率、周转与 hog/expansion 因子
LSF 主机与负载 Grafana →「LSF 调度」→ 主机与节点资源 主机状态表、r1m 负载、CPU 利用率、可用内存与临时空间
LSF 公平性与用户 Grafana →「LSF 调度」→ 公平性与用户 队列 FAIRSHARE 份额表、用户/组作业数与限额
LSF 是否卡在 License Grafana →「LSF 调度」→ 跨域联动 LSF 运行作业数 vs FlexLM 许可占用、Lustre 容量
许可服务健康 Grafana →「FlexLM 许可」→ 服务与采集健康 lmgrd / vendor daemon 状态、角色(MASTER/BACKUP)、版本、采集耗时与解析健康
许可池容量与水位 Grafana →「FlexLM 许可」→ 许可池容量与水位 发行总量 / 在用 / 空闲、各厂商利用率、Top 10 feature 利用率
谁在占用许可 Grafana →「FlexLM 许可」→ 占用与持有者 占用用户数、Top 用户占用数、最久未释放的 feature(无 checkout 时为空属正常,非故障)
许可被拒 Grafana →「FlexLM 许可」→ 拒绝与争抢 flexlm_license_denied_total 的 15 分钟增量与累计、利用率与拒绝联看
许可到期 Grafana →「FlexLM 许可」→ 到期与版本 最近到期倒计时、各窗口内到期 feature 数、许可文件 present / served 一致性
许可结构 Grafana →「FlexLM 许可」→ 许可结构 各厂商 counted / uncounted / node-locked 的 feature 数(Cadence 侧全部为 uncounted,无容量语义)
许可与作业联动 Grafana →「FlexLM 许可」→ 跨域联动 许可占用 vs Slurm/LSF 运行作业数、许可空闲 vs Slurm License 阻塞
Slurm 调度等待 Grafana →「Slurm 集群」 Pending 当前等待、运行作业提交到启动的 avg/max
原始查询 Prometheus(prometheus.rainchen.top) up{job=~"external-node-exporters.*"}
有 Pod 起不来 Grafana → Alerting,或 Prometheus kube_pod_status_phase{phase="Pending"} == 1
告警历史 Grafana → Alerting,或 Alertmanager 界面 firing / resolved

需要重点盯的告警

告警 阈值 级别 含义
ExternalHostNodeExporterDown up == 0 持续 5m critical 主机失联或采集进程挂了(注意:不是 EnvHostDown,抑制规则 inhibit_rules 以该名为准)
磁盘可用空间 <15% (15m) / <8% (5m) warning / critical 分区将写满
inode 使用率 <10% / <5% warning / critical 小文件写满
内存可用 <10% (10m) warning 可能触发 OOM
CPU iowait / steal 均值 >20% (15m) warning 存储或虚拟化层饱和
systemd 单元失败 state="failed" (10m) critical 基础设施服务异常
时间同步偏移 >0.05s (10m) / >0.5s warning / critical 指标时间戳失真
Env{Pod}StuckPending / EnvPodContainerCreateFailed 10m warning 集群侧:Pod 卡在挂载/调度/Init 或镜像拉不到
EnvSlurmMetricsDown / EnvLustreMetricsDown / EnvLsfMetricsDown / EnvFlexlmMetricsDown 对应 *_up == 0 持续 10m warning 领域采集器失效(该领域面板会停更,见场景 7)
EnvSlurmCtldDown slurm_ctld_up == 0 持续 5m critical Slurm 控制端不可用,作业提交/调度受影响
EnvSlurmPartitionDown slurm_partition_avail == 0 15m warning 分区被置 down
EnvSlurmJobsBacklog slurm_jobs{state="PENDING"} > 20 30m warning Slurm 作业积压
EnvSlurmPendingWaitHigh Pending 最大等待 >30m 持续 15m warning 排队作业等待时间过长
EnvSlurmDispatchWaitHigh 平均调度等待 >10m 持续 15m warning 提交到开始运行的调度延迟过高
EnvLustreFsUsageHigh 客户端已用率 >85% 持续 15m warning Lustre 文件系统容量告急(客户端视角)
EnvLustreClientDeviceDown lustre_client_device_up == 0 持续 5m critical 客户端设备(mgc/lov/lmv/mdc/osc)非 UP,作业读写该文件系统会直接报错
EnvLustreClientEviction 15m 内有新增驱逐 warning 客户端被服务端驱逐(RPC 超时 / 锁冲突 / 网络抖动)
EnvLustreClientRpcResend 15m 内重传新增 >10 warning 客户端到 OSS 的 RPC 重传偏多
EnvLustreOstCapacityHigh / EnvLustreMdtCapacityHigh 服务端已用率 >85% 持续 15m warning OST / MDT 服务端容量告急(OSS/MDS 自查,不依赖客户端)
EnvLustreInodeUsageHigh inode 使用率 >85% 持续 15m warning 小文件写满 inode(EDA 场景常见)
EnvLustreOstGrantPending lustre_ost_grant_bytes{type="pending"} > 0 持续 15m warning 写入授权受阻,写入将变慢(容量耗尽前兆)
EnvLustreMdtLatencyHigh / EnvLustreOstLatencyHigh 平均延迟 >20 ms 持续 15m warning 元数据 / OST 操作延迟显著劣化(阈值偏保守,待有负载后校准)
EnvLsfMetricsDown lsf_up == 0 持续 10m warning LSF 采集失败(LSF 环境变量缺失、二进制不可用或查询失败)
EnvLsfClusterUnavailable lsf_cluster_status == 0 持续 5m critical LSF 集群状态非 ok
EnvLsfMasterDown lsf_master_up == 0 持续 5m critical LSF 主控不可达,全集群无法提交/调度
EnvLsfMbatchdDown lsf_mbatchd_up == 0 持续 5m critical mbatchd 不可用,作业调度停止
EnvLsfHostAbnormal unreach/unavail/unusable 15m warning LSF 主机不可用(closed_Full 不算异常)
EnvLsfServersNotOk 服务器 unreachable/unavailable > 0 持续 15m warning 调度器侧有服务器不可达/不可用
EnvLsfQueueBacklog 队列 PEND > 50 持续 30m warning LSF 单队列积压
EnvLsfJobsBacklog 全局 PEND > 20 持续 30m warning LSF 全集群排队作业积压
EnvLsfPendingWaitHigh 最长排队等待 > 30m 持续 15m warning 排队等待时间过长
EnvLsfDispatchWaitHigh 平均调度等待 > 10m 持续 15m warning 提交到开始运行延迟过高
EnvLsfPendingReasonSpike 单个 Pending 原因 > 10 持续 30m info 某类等待原因持续升高(先观察)
EnvLsfJobExitedHigh 窗口内异常退出作业 > 5 持续 30m warning 近 1 小时异常退出作业偏多
EnvFlexlmServerDown flexlm_server_up == 0 5m critical 许可服务器不可用,EDA 工具会取不到许可
EnvFlexlmDaemonDown flexlm_vendor_daemon_up == 0 5m critical vendor daemon 挂了,该厂商全部 feature 取不到许可(lmgrd 仍显示 UP,不能只看服务器状态)
EnvFlexlmOutputParseFailed flexlm_parse_ok == 0 and flexlm_collect_success == 1 10m warning lmstat 能跑但解析不出 feature,容量面会显示为空(与「确实没有 feature」表现相同)
EnvFlexlmCheckoutParseFailed flexlm_checkout_parse_failed > 0 10m warning 用户行格式与解析器不一致,此时「无占用」不可信,须抓样本修正解析器
EnvFlexlmDeniedLogUnavailable flexlm_license_denied_log_available == 0 15m warning lmgrd 日志读不到,denied 恒为 0,「没有拒绝」与「统计不到」无法区分
EnvFlexlmCollectSlow flexlm_collect_duration_seconds > 30 10m warning 采集耗时接近 60s 周期,指标可能更新不及时
EnvFlexlmLicenseExhausted in_use >= total 持续 10m warning 许可用尽,新请求排队或被拒
EnvFlexlmLicenseDenied increase(flexlm_license_denied_total[15m]) > 0 持续 5m warning 最近 15 分钟出现新的许可拒绝
EnvFlexlmLicenseExpiring flexlm_license_expiring_features{window="30d"} > 0 持续 1h warning 有 feature 将在 30 天内到期,到期后该 feature 无法检出
EnvFlexlmLicenseFileUnreadable file_present=1 and file_readable=0 30m warning 许可文件在盘上但解析不了,到期统计与结构缺失
Watchdog(心跳) 恒定 firing,每 24h 一封 info(P3) 设计如此:收到它说明告警链路本身是活的;超过 24h 收不到才说明链路断了

8. 故障处置

场景 1:某台主机 target down(Grafana「失联主机」> 0)

症状:up{instance="slurm-work-01:9100"} == 0;收到 EnvHostDown 邮件。

诊断

# 1) 主机是否可达
timeout 6 ssh -o BatchMode=yes -o ConnectTimeout=3 root@192.168.31.18 hostname
# 2) 采集进程与端口
ssh root@192.168.31.18 "systemctl is-active prometheus-node-exporter; ss -lntH | grep ':9100'"
# 3) 服务日志
ssh root@192.168.31.18 "journalctl -u prometheus-node-exporter -n 50 --no-pager"
# 4) 防火墙规则是否还在
ssh root@192.168.31.18 "firewall-cmd --list-rich-rules | grep 9100"

处置

  • 1) 失败 → 主机或网络问题,属主机侧故障,不在本工程范围;
  • 2) inactive/failed → ssh root@<ip> "systemctl restart prometheus-node-exporter"; 仍失败看 3) 的日志(bind: permission denied 走场景 2);
  • 端口无监听但服务 active → 检查 drop-in 是否被改动:ssh root@<ip> "systemctl cat prometheus-node-exporter", 与配置期望比对后重跑 deploy;
  • 4) 规则缺失(例如 firewalld 被重载/重建)→ .venv/bin/python main.py deploy 会补回。

验证:.venv/bin/python main.py verify 通过;Prometheus 中该 instance 的 up 回到 1(约 30s 内)。

场景 2:node-exporter 启动失败,日志报 bind: permission denied

症状:systemctl status prometheus-node-exporter 显示反复重启;journalctl 出现 listen tcp :9100: bind: permission denied。

诊断

ssh root@192.168.31.16 "getenforce; journalctl -u prometheus-node-exporter -n 30 --no-pager | grep -iE 'denied|avc'"
ssh root@192.168.31.16 "grep 'type=AVC' /var/log/audit/audit.log | tail -5"

处置(高危:改 SELinux 端口标签,全局生效)

实测结论(2026-09-30):本环境的 EPEL node-exporter 以 User=prometheus 运行, 未落入受限域,8 台 Enforcing 主机上均正常绑定 9100 —— 无需改端口标签。 以下步骤仅在该结论被推翻(换了包、换了策略)时使用。

先确认 9100 当前标签与实际占用:

ssh root@192.168.31.16 "semanage port -l 2>/dev/null | grep -w 9100 || echo 'semanage 不可用'"
  • 若 semanage 不可用,先装 dnf install -y policycoreutils-python-utils;
  • 若需放行:semanage port -m -t http_port_t -p tcp 9100(注意:9100 现属 hplip_port_t, 改标签会影响 hplip;本环境未使用打印服务);
  • 改完 systemctl restart prometheus-node-exporter。

验证:端口监听 + main.py verify 通过。 若与本 SOP 第 5.3 步的实测结论不一致,请把新结论回写到 docs/SOP.md 与配置中。

场景 3:收不到告警邮件

症状:Grafana/Alertmanager 已显示 firing,但邮箱无信。

诊断

# 1) Alertmanager 运行配置里是否有我们的 receiver
kubectl --kubeconfig /home/rain/.kube/config get secret \
  alertmanager-kube-prometheus-stack-alertmanager-generated -n monitoring \
  -o jsonpath='{.data.alertmanager\.yaml}' | base64 -d | grep -A3 env-monitor-email
# 2) Alertmanager 是否在报发送失败
kubectl --kubeconfig /home/rain/.kube/config logs -n monitoring \
  alertmanager-kube-prometheus-stack-alertmanager-0 --tail=80 | grep -iE 'smtp|error|notify'

处置

  • 1) 无 env-monitor-email-* → 路由未生效:.venv/bin/python main.py deploy 重新应用 (含 helm upgrade,--no-hooks);
  • 2) 出现 535/authentication failed → SMTP 授权码过期,更新 ~/.secrets/dell-r620-monitor.env 中的 DELL_R620_SMTP_AUTH_PASSWORD 后重跑 deploy;
  • 出现 connection refused/timeout → 操作机能出网但 SMTP 被限,检查 smtp.163.com:25 连通性;
  • 告警是 info 级 → 设计上不发信,去 Grafana 大盘看。

验证:邮箱收到主题形如 [主机P1 FIRING] EnvHostDown @ <instance> 的邮件。

场景 4:大盘无数据或变量为空

症状:打开「环境总览」所有面板 No data;或 cluster/role 变量下拉为空。

诊断

# 1) 指标是否有数据(先排除采集问题)
.venv/bin/python main.py verify
# 2) ConfigMap 是否存在且带 sidecar 标签
kubectl --kubeconfig /home/rain/.kube/config get configmap env-monitor-overview \
  -n monitoring -o jsonpath='{.metadata.labels}'
# 3) Grafana sidecar 是否已导入
kubectl --kubeconfig /home/rain/.kube/config logs -n monitoring \
  -l app.kubernetes.io/name=grafana -c grafana-sc-dashboard --tail=50 | grep -i overview
# 4) 大盘生成物与精简源是否一致(手改过 manifests 或改完精简源没重新生成时先查这条)
.venv/bin/python main.py build-dashboards --check

处置

  • 1) 有主机 down → 先按场景 1 处理;
  • 2) 标签缺 grafana_dashboard: "1" → 重跑 deploy 修正;
  • 3) sidecar 报错/未导入 → 重启 Grafana Pod 触发重新扫描;
  • 仍无数据 → 检查面板 datasource uid 是否为 prometheus(与 chart 默认一致)。

验证:变量下拉能列出 5 个集群、面板出现曲线。

场景 5:drift / deploy 报「状态探测失败(unknown)」

症状:命令直接中止并提示某些主机探测失败。

原因:这是刻意设计——三态探测里 unknown 代表「连不上/探不到」, 按规范必须中止,绝不当成「需要变更」去盲目改动。

处置

# 先确认是不是操作机 SSH 通道问题
timeout 6 ssh -o BatchMode=yes -o ConnectTimeout=3 root@192.168.31.16 hostname
ls -l /root/.ssh/id_*          # 以 root 运行工程时,密钥取自 /root/.ssh
  • SSH 不通 → 排查免密/密钥/网络;
  • 只有个别主机失败 → 该主机可能正在重启或 sshd 异常,恢复后重跑;
  • 确认是集群侧探测失败 → 检查 kubectl --kubeconfig <配置文件里的路径> version。

验证:.venv/bin/python main.py drift 退出码 0 或 1(1 = 有漂移但不致命)。

场景 6:Pod 长时间卡在 Init:0/1 或 Terminating

症状:收到 EnvPodStuckPending 邮件;Pod 卡在 Init:0/1(或 Terminating)超过 10 分钟; 事件里 kubelet 的最后一条是 operationExecutor.VerifyControllerAttachedVolume started,之后无进展。 重启 kubelet、清理孤儿 sandbox、强制删 Pod 重建均无效。

诊断(先按顺序排除;2026-09-30 的实例已逐项排除过,可直接复用这套清单)

# 1) 卷到底挂上了没有(挂上了说明不是存储问题)
ssh root@192.168.31.14 "journalctl -u kubelet --since '20 min ago' | grep -i 'MountDevice succeeded'"
# 2) 是不是镜像拉不到(本环境集群侧 ghcr.io 不可达,属已知约束)
ssh root@192.168.31.14 "journalctl -u kubelet --since '20 min ago' | grep -ciE 'ErrImagePull|ImagePullBackOff'"
# 3) 节点侧是否有该 Pod 的容器/sandbox 残留
ssh root@192.168.31.14 "crictl pods | grep <pod 名片段>"
# 4) 有无 NFS/挂载层内核报错
ssh root@192.168.31.14 "journalctl -k --since '20 min ago' | grep -iE 'nfs|rpc|stale'"
# 5) 磁盘/内存是否够
ssh root@192.168.31.14 "df -h /var/lib/containerd; free -g"

处置

  • 首选:把 Pod 换到其它节点(2026-09-30 实测立即恢复),不要在单节点上反复 force delete / 重启 kubelet 耗时间;临时做法是给 Deployment/StatefulSet 加 nodeSelector 指向健康节点;
  • 该现象 2026-09-30 在 k8s-node-02 出现,复现实验(新建 PVC + 挂载 + init 容器) 11 秒即通过、无脏状态残留,故判为当时的临时状态而非节点缺陷; 完整排除清单与预防建议见 node02-init-stuck-20260930/20260930-k8s-node-02-Pod卡Init故障报告.md;
  • Grafana 已用 manifests/06-grafana-node-pin.yaml 钉在 k8s-node-03,暂不要让它回到 node-02(解除条件见该故障报告第 8 节);
  • 不要在未确认节点侧无容器时对 PVC 动手(可能触发不可逆的卷删除)。

验证:Pod 进入 Running 且 READY 到位;kubectl get pvc -n monitoring 全部 Bound; 告警自动 resolved。

场景 7:某个领域的指标缺失或停更

症状:Grafana 的「Slurm 集群」/「Lustre 存储」/「LSF 调度」/「FlexLM 许可」某块面板显示 「无数据」;或收到 EnvSlurmMetricsDown / EnvLustreMetricsDown / EnvLsfMetricsDown / EnvFlexlmMetricsDown 告警。

诊断(以 Lustre MDS .21 为例;其它领域把 lustre 换成 slurm / lsf / flexlm)

FlexLM 专有分支:本领域有四种「看着像没有数据」的情形,前三种是故障、后一种是正常, 先看自省指标再动手(.29 上执行):

ssh root@192.168.31.29 'grep -E "^flexlm_(up|collect_success|parse_ok|lmstat_rc|collect_duration|checkout_parse_failed|license_denied_log_available)" /var/lib/node_exporter/textfile/flexlm.prom'
  • parse_ok=0 而 collect_success=1 → 故障:lmstat 能跑但输出格式变了, 容量面为空是解析失败所致(对应 EnvFlexlmOutputParseFailed);
  • checkout_parse_failed>0 → 故障:用户行解析失败,「当前无占用」不可信 (对应 EnvFlexlmCheckoutParseFailed),须抓 lmstat -a 的用户行样本修正解析器;
  • license_denied_log_available=0 → 故障:lmgrd 日志读不到,denied 恒 0 属统计缺失, 不是「没有拒绝」;
  • collect_duration 接近 60 → 隐患:采集赶不上周期,指标会时断时续;
  • 正常:「占用与持有者」整组为空(当前无任何 checkout 时本就无数据); Cadence 厂商的容量类面板为空(该厂商 604 个 feature 全部是 uncounted,没有占用率概念)。
# 1) 采集器的单元状态(oneshot 服务跑完即退,inactive 属正常,关键看 timer)
ssh root@192.168.31.21 'systemctl status env-lustre-metrics.timer --no-pager | head -8'
# 预期:Active: active (waiting)

# 2) 最近一次执行的输出与报错
ssh root@192.168.31.21 'journalctl -u env-lustre-metrics.service -n 30 --no-pager'

# 3) 手工跑一次看采集内容(参数取自 unit 的 ExecStart)
ssh root@192.168.31.21 '/usr/local/bin/env-lustre-metrics --bin-dir=/usr/sbin --cluster=lustre --stdout'
# 预期:首行 lustre_up{cluster="lustre"} 1,其后为各指标

# 4) 指标文件是否生成、node-exporter 是否带出
ssh root@192.168.31.21 'ls -l /var/lib/node_exporter/textfile/'
ssh root@192.168.31.21 'curl -s localhost:9100/metrics | grep -c "^lustre_"'
# 预期:文件存在且非空;计数 > 0

处置

  • 若第 3 步输出 lustre_up 0:该领域命令不可用(如客户端未挂载 Lustre、二进制路径变更、 NFS 上的 LSF 目录不可达)→ 核对 config/env-monitor.yaml 的 collectors.<领域>.bin_dir 与 probe_cmd,必要时先跑 precheck 看门禁结论;
  • LSF 专有:若 lsf_up 0 且 journalctl -u env-lsf-metrics.service 里出现 lsb_init: 或 Unable to open file lsf.conf,说明 systemd 单元缺少 LSF 环境变量 → 核对 config/env-monitor.yaml 的 collectors.lsf.extra_env(应含 LSF_ENVDIR 与 LSF_SERVERDIR),改后重跑 .venv/bin/python main.py deploy; 现场快速判断可执行 ssh root@192.168.31.23 'systemctl cat env-lsf-metrics.service | grep Environment';
  • Lustre 专有:本领域按节点角色自动裁剪采集段,排查时先确认角色 —— lctl get_param -l 'mdt.*'(MDS)/ 'obdfilter.*'(OSS)/ 'llite.*'(客户端)是否存在对应参数; 另有两处看起来像故障、其实是正常的现象: ① 「磁盘层 IO」(brw_stats)在空载时本来就没有数据行,.22 上没有 lustre_ost_disk_io_ios 属正常,有作业负载后才会出现; ② 「客户端体验」与「容量」类指标只在挂载了 Lustre 的节点(.28 hpc-submit)上产生, 且其 cluster 标签是 hpc(由 ServiceMonitor relabel 按节点所属集群生成,会覆盖指标文件 里的同名值)—— Lustre 大盘已对这两类面板取消集群过滤,若手工改过大盘把过滤加回去, 选中 lustre 时它们会整片消失;
  • 若 journalctl 报 unrecognized arguments:目标机上的脚本版本旧于配置(脚本接口变更后未更新) → 重跑 .venv/bin/python main.py deploy,脚本 sha256 变化会自动触发重新下发;
  • 若指标文件正常但 Prometheus 无数据 → 按场景 1 查抓取链路(up{instance="<name>:9100"});
  • 若只是某一块面板空:先确认该指标名是否真实存在(curl -s localhost:9100/metrics | grep '^lustre_'), 再看大盘查询表达式是否写错标签。

验证:curl -s localhost:9100/metrics | grep '^lustre_' 有输出,且 Grafana 对应面板恢复。

9. 安全与权限

账号与权限模型

范围 账号 权限
目标主机 root(SSH 免密,仅操作机可用) 装包、systemd、firewalld、SELinux
K8s 配置中 kubernetes.kubeconfig 指向的凭证 monitoring 命名空间读写 + 集群级读 CRD
Grafana/Alertmanager 见第 2 节凭据表 —

端口与访问控制:目标机仅新增 9100/tcp,且限定源 10.244.0.0/16; node-exporter 以 cmdline collector 关闭运行,不暴露进程命令行。

证书/密钥:本工程不签发证书;helm 与 kubectl 使用既有 kubeconfig; SMTP 授权码轮换步骤:更新 ~/.secrets/dell-r620-monitor.env → 重跑 .venv/bin/python main.py deploy(会重新渲染并 helm upgrade)。

风险变更标记:删除文件、覆盖配置、启停服务属高危动作, 实现体会在日志中以「【高危】」前缀醒目标记,并在 precheck 报告里列出。

10. 容量与性能

当前水位基线(2026-09-29 实测)

项 数值
Prometheus head series 76,135
采样速率 2,680 samples/s
TSDB 占用 4.02 GiB / PVC 100 GiB
Prometheus Pod 内存 634 Mi(request 2Gi / limit 4Gi)
保留期 15 天 / retentionSize 90 GiB
本次新增预估 +15~22%(约 +1.1~1.7 万 series、+400~600 samples/s)

扩容触发条件:head series 超过 13 万、或 Prometheus Pod 内存持续 >3 GiB、 或 TSDB 占用超过 70 GiB 时,按顺序考虑:① 提高 scrape_interval; ② 增加 recording rules 降基数;③ 扩 PVC / 调 retentionSize。

扩容操作:改 prometheus_deploy/values.yaml 后按该工程 SOP 执行 (不在本工程范围)。

已知瓶颈:Prometheus 单副本、TSDB 落在 nfs-csi-hdd(宿主 Dell R620), 与宿主 NFS 属同源故障域——宿主故障会同时影响被监控对象与监控数据。

11. 附录

术语

术语 说明
USE Utilization / Saturation / Errors,主机层分析框架
cluster / role 本工程给目标主机打的标签,值来自配置 nodes 段的键名与 role 字段
三态探测 done(已达标,跳过)/ pending(需变更)/ unknown(探不到,中止)
漂移 实机与配置期望态之间的差异,用 main.py drift 查看

相关文档与交付物

文档 用途
docs/SOP.md 本次变更的实施、验证与回滚
docs/RUNBOOK.md 本文件
config/env-monitor.yaml 配置唯一真源
backup/README.md 备份台账
reports/ 预检查与漂移报告
utils/probe/ 变更前的前置只读实测脚本

修订记录

日期 修改人 变更内容
2026-09-29 rain 首版。随 P0(14 台非 K8s 主机接入)产出

来源:/home/rain/Documents/k8s_ins/env-monitor-deploy/docs/RUNBOOK.md | 最后更新:2026-10-02 12:43(由 build/sync.py 同步,请勿在站点侧修改)