起因
装了 Prometheus + Grafana 后能看图了,但"半夜 3 点磁盘满了"还得
有人盯仪表盘才发现。要把"触发某指标条件"自动转成 push 告警。
Alertmanager 是 Prometheus 生态官方告警分发组件。
解决方案
1. 写告警规则(Prometheus 端)
/etc/prometheus/rules/node.yml:
groups:
- name: node-alerts
interval: 30s
rules:
- alert: NodeDown
expr: up{job="node"} == 0
for: 2m
labels:
severity: critical
team: ops
annotations:
summary: '节点 {{ $labels.instance }} 离线'
description: 'Prometheus 已经 2 分钟无法 scrape {{ $labels.instance }}'
- alert: HighCPU
expr: 100 - avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100 > 85
for: 10m
labels:
severity: warning
annotations:
summary: '{{ $labels.instance }} CPU > 85% 持续 10 分钟'
- alert: DiskAlmostFull
expr: 100 - node_filesystem_avail_bytes{mountpoint="/"} * 100 / node_filesystem_size_bytes{mountpoint="/"} > 90
for: 5m
labels:
severity: critical
annotations:
summary: '{{ $labels.instance }} 根分区 > 90%'
description: '目前 {{ $value | humanizePercentage }}'
- alert: MemoryPressure
expr: 100 * (1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) > 92
for: 15m
labels:
severity: warning
关键点:
expr:PromQL 表达式,结果非空时触发for:持续多久才真触发(避免瞬间抖动告警)labels:可以路由用(severity / team)annotations:人读的内容,模板支持{{ $labels.x }}和{{ $value }}
prometheus.yml 引入:
rule_files:
- /etc/prometheus/rules/*.yml
alerting:
alertmanagers:
- static_configs:
- targets: ['localhost:9093']
reload Prometheus:
curl -X POST http://localhost:9090/-/reload
UI 看告警状态:http://prom:9090/alerts,三种状态:Inactive / Pending / Firing。
2. 装 Alertmanager
curl -fsSL https://github.com/prometheus/alertmanager/releases/latest/download/alertmanager-0.27.0.linux-amd64.tar.gz \
| sudo tar xz -C /opt/
sudo ln -s /opt/alertmanager-0.27.0.linux-amd64 /opt/alertmanager
sudo useradd -rs /bin/false alertmanager
sudo mkdir -p /var/lib/alertmanager
sudo chown -R alertmanager:alertmanager /var/lib/alertmanager
3. 配置 Alertmanager
/etc/alertmanager/alertmanager.yml:
global:
resolve_timeout: 5m
smtp_smarthost: 'smtp.example.com:587'
smtp_from: '[email protected]'
smtp_auth_username: 'notifier'
smtp_auth_password: '...'
# 路由树
route:
receiver: default
group_by: ['alertname', 'instance']
group_wait: 30s # 第一条告警等 30s 看有没有同组的
group_interval: 5m # 同组下一批告警最少间隔
repeat_interval: 4h # 同告警重复发的最短间隔
routes:
- matchers:
- severity = critical
receiver: pagerduty
group_wait: 10s
repeat_interval: 1h
- matchers:
- severity = warning
- team = ops
receiver: slack-ops
inhibit_rules:
- source_matchers: [severity="critical"]
target_matchers: [severity="warning"]
equal: ['instance']
# 同一台机器既有 critical 又有 warning,warning 被抑制(避免噪音)
receivers:
- name: default
email_configs:
- to: '[email protected]'
- name: slack-ops
slack_configs:
- api_url: 'https://hooks.slack.com/services/...'
channel: '#alerts-ops'
title: '{{ .CommonAnnotations.summary }}'
text: |
{{ range .Alerts }}
*{{ .Annotations.summary }}*
{{ .Annotations.description }}
severity: {{ .Labels.severity }}
{{ end }}
- name: pagerduty
pagerduty_configs:
- service_key: '<PD key>'
- name: dingtalk
webhook_configs:
- url: 'https://oapi.dingtalk.com/robot/send?access_token=...'
send_resolved: true
钉钉 webhook 需要特定 JSON 格式,
通常需要中间 adapter(prometheus-webhook-dingtalk)转换。
systemd unit:
[Service]
User=alertmanager
ExecStart=/opt/alertmanager/alertmanager \
--config.file=/etc/alertmanager/alertmanager.yml \
--storage.path=/var/lib/alertmanager
Restart=on-failure
sudo systemctl enable --now alertmanager
4. 测试
手动触发一条假告警:
curl -XPOST http://alertmanager:9093/api/v2/alerts -d '
[{
"labels": {"alertname": "TestAlert", "severity": "critical", "instance": "test"},
"annotations": {"summary": "测试告警"},
"startsAt": "2026-05-24T10:00:00Z"
}]'
应该几秒内收到 Slack / 邮件。
5. 抑制 + 静默
# 系统维护期间静默
amtool silence add alertname=NodeDown instance=app1.example.com \
--duration=2h --comment 'planned maintenance'
amtool silence query
amtool silence expire <id>
或 Alertmanager UI(端口 9093)有 silence 表单。
效果
- 告警从"刷仪表盘" → "手机 push"
- 通过 group_by + group_interval 把"集群批量告警"合并成几条消息,
不再被刷屏 - inhibit 让"机器挂了之后机器上每个服务都告警"自动只剩一条 NodeDown
- on-call 工程师 MTTR 从 30 分钟(发现 + 上线诊断)降到 5 分钟
几个最佳实践
-
for: 5m不要省:磁盘 90% 持续 5 分钟才真告警,避免 cron 任务
瞬间冲高引起假警 -
每条 alert 配 runbook 链接:annotation 加
runbook_url,告警
消息里点击直达"出现 X 怎么处理"文档 -
不要告警一切:CPU 80% 不需要立刻人工干预,写到 daily report
就好。半夜 page 应当是"现在不处理业务挂"级别 -
repeat_interval: 4h平衡:太短刷屏;太长重要告警睡过 -
定期 review alert noise:跑
amtool alert query看哪些告警
反复 firing 没人理 → 要么调阈值要么删
踩过的坑
-
rule reload 没生效:Prometheus reload
/-/reload端点默认禁用,
要--web.enable-lifecycle启动。 -
告警时间戳错乱:Prometheus / Alertmanager 时区不一致 → UI 显示
告警是几年前的。两端都 UTC。 -
expr 写错没语法报错:Prometheus 接受语法对但语义错的表达式
(如metric > 100而 metric 单位是 GB),跑出来永远空。在
Prometheus UI Graph 选项卡先跑 expr 看结果再写规则。 -
Slack webhook URL 进 git:泄露了被人乱发消息。放 env / secret
或 alertmanager 的file:引用:
yaml api_url_file: /etc/alertmanager/slack_url -
inhibit_rules 的
equal字段不一致:source 和 target 没共同
label 时 inhibit 不生效。仔细 check label 列表。
登录后参与评论。