📈 第05章 · 告警规则与 Alertmanager

rules + 告警路由

告警规则与 Alertmanager

数据全了,也画成图了,但监控的最终目的是出事时立刻有人知道。这就是告警的活:Prometheus 根据规则评估表达式,命中后把"报警"交给 Alertmanager,由它负责"去告诉谁、怎么告诉、几轮提醒"。这一章从规则文件讲起,再到 Alertmanager 的配置与路由。

告警链路长什么样

   规则评估(Prometheus)   →   生成告警   →  Alertmanager   →   接收方(邮件/飞书/钉钉)
   rule_files             firing/pending   /api/v2/alerts      route + receiver
  • Prometheus 定期(默认 evaluation_interval,这里 15s)评估规则,命中条件进入 pending,持续满足超过 for 时长进入 firing;
  • Alertmanager 收到 firing 告警,按路由规则分发到响应的接收渠道。

rule_files:挂规则文件

告警规则写在独立 YAML 文件里,由 rule_files 加载(第 2 章说过目前是注释状态,要用就得打开):

rule_files:
  - "/etc/prometheus/rules/alert.rules.yml"

易错 当前 /etc/prometheus/prometheus.yml 的 rule_files 下两行都是注释。不取消注释,就算规则文件存在也永远不会评估——这是"为什么告警不触发"的高频元凶。路径写绝对路径最稳。

规则文件结构

一个规则文件包含若干 groups,组里是若干常用 rules:

groups:
  - name: node_rules
    rules:
      - record: job:node:up         # 记录规则:预计算,存成新指标
        expr: up{job="node"}
      - alert: InstanceDown          # 告警规则
        expr: up{job="node"} == 0
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "节点 {{ $labels.instance }} 已宕机"
字段 含义
record 记录规则,把表达式算成新指标存起来复用
alert 告警规则名称
expr 触发条件表达式,为真则进入告警
for 持续多久才真正 firing,能避免瞬时抖动误报
labels 附加标签(最常用 severity)
annotations 告警说明文字,可用模板变量 $labels/$value

三套实用告警规则

结合本机实际,写一组可直接用的:

groups:
  - name: alerting_rules
    rules:
      - alert: InstanceDown
        expr: up{job="node"} == 0
        for: 1m
        labels: { severity: critical }
        annotations:
          summary: "节点 {{ $labels.instance }} 无响应"
          description: "Prometheus 已连续 1 分钟抓取失败。"

      - alert: HighCPUUsage
        expr: 100 - (avg(irate(node_cpu_seconds_total{mode="idle"}[5m]))*100) > 85
        for: 5m
        labels: { severity: warning }
        annotations:
          summary: "CPU 使用率过高 ({{ $value }}%)"
          description: "近 5 分钟 CPU 超过 85%,需关注是否被压满。"

      - alert: DiskAlmostFull
        expr: 1 - node_filesystem_free_bytes{mountpoint="/"}/node_filesystem_size_bytes{mountpoint="/"} > 0.85
        for: 10m
        labels: { severity: warning }
        annotations:
          summary: "根分区即将用满 ({{ $value | humanizePercentage }})"
          description: "根分区使用率连续 10 分钟超过 85%,建议清理日志。"

提示 for 是误报的"减压阀"。CPU 瞬时冲高可能是正常业务尖峰,for: 5m 表示持续 5 分钟才真正告警;而 InstanceDown 本身已是强信号,for: 1m 就够。新规则先给一个宽松的 for,跑几天观测再收紧。

告警生命周期

状态 含义
pending 表达式命中,但还没持续到 for 阈值
firing 已持续超过 for,真正发往 Alertmanager
resolved 条件恢复满足,Alertmanager 发"恢复"通知

用 CLI 查看当前告警状态:

curl -s "localhost:9090/api/v1/alerts" | python3 -m json.tool

Alertmanager:收件与分发

Alertmanager 是独立二进制(默认端口 9093),负责去重、分组、路由、抑制与静默。配置示例 alertmanager.yml:

route:
  group_by: ['alertname']
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 4h
  receiver: 'default'
  routes:
    - match: { severity: critical }
      receiver: 'pager'

receivers:
  - name: 'default'
    webhook_configs:
      - url: 'http://localhost:8080/notify'
  - name: 'pager'
    email_configs:
      - to: 'oncall@example.com'
配置段 作用
route 告警路由:按标签匹配决定发谁
group_by 按什么维度打包(避免刷屏)
group_wait/interval 打包前的等待窗口
repeat_interval 重复提醒间隔
inhibit_rules 抑制规则:高阶告警压制低阶
receivers 具体渠道(邮件/webhook/飞书/钉钉)

易错/安全 目前这台服务器的 alerting.alertmanagers 指向 localhost:9093,但 9093 并未监听,即 Alertmanager 尚未安装启动。配置就绪≠链路通了;要用告警,必须先安装并启动 Alertmanager,再确认 9093 在监听。

检查链路是否打通

# 1. 配置文件校验
promtool check config /etc/prometheus/prometheus.yml
promtool check rules /etc/prometheus/rules/alert.rules.yml

# 2. 重载生效
systemctl reload prometheus

# 3. 查看已加载的规则
curl -s "localhost:9090/api/v1/rules" | python3 -m json.tool | grep -E '"name"|"state"'

# 4. 确认告警、Alertmanager 可达
curl -s "localhost:9093/api/v2/alerts"   # 需 Alertmanager 在跑

易错点

  • rule_files 忘了取消注释:规则文件存在但 Prometheus 根本不知道。
  • for 太小:生产里瞬时抖动会频繁误报,新规则先宽松再收紧。
  • alerting.alertmanagers 指向一个没跑的 9093:配置合法但告警始终发不出去。
  • expr 比较方向写反:如 CPU 用了 > 85 变成"低于85告警",检查阈值方向。
  • 模板变量用错:{{ $value }} 得到的是数值,{{ $labels.instance }} 得到主机;想要百分比要用 humanizePercentage。

相关命令

promtool check rules <file>、curl -s localhost:9090/api/v1/rules、curl -s localhost:9090/api/v1/alerts、curl -s localhost:9093/api/v2/alerts、systemctl reload prometheus。