Prometheus Alertmanager 详解及实战
一、概述
Alertmanager 是 Prometheus 生态的专属告警调度组件,承接 Prometheus Server 推送的告警数据,实现告警的去重、分组、抑制、静默、分级分发。在 Prometheus 架构中,告警由两个相互独立的组件配合完成:
-
Prometheus Server:根据配置的告警规则周期性计算指标,当规则触发时生成告警并推送给 Alertmanager。
-
Alertmanager:专注于告警的聚合、路由、静默与通知,最终通过接收器发送给指定用户。
举个典型场景:当 10 个节点同时宕机,如果直接发送 10 条通知,运维人员会被信息淹没。Alertmanager 通过分组机制将相同类型的告警合并为一条通知,显著提升可读性。
核心区别:Prometheus 负责“判定告警是否产生”,Alertmanager 负责“管控告警如何发送”。
二、Alertmanager 核心架构与工作流程
2.1 核心功能
| 功能 | 说明 |
|---|---|
| 告警分组(Grouping) | 将同一类型、同一主机、同一业务的多条告警合并为一条批量通知,避免告警轰炸 |
| 告警去重(Deduplication) | 相同重复告警自动合并,避免短时间内频繁推送 |
| 告警抑制(Inhibition) | 重大故障触发时,抑制衍生的次要告警(如主机宕机后抑制该主机所有容器告警) |
| 告警静默(Silences) | 临时屏蔽指定告警,适配维护升级、停机演练场景 |
| 路由分发(Routing) | 根据告警标签,将不同级别、不同业务的告警推送至不同接收渠道(钉钉、企业微信、邮件、短信) |
| 告警防抖 | 支持配置等待时间、持续告警时间,避免瞬时抖动触发误告警 |
2.2 完整告警链路


2.3 告警的两种状态(Prometheus 侧)
-
Pending(待定):指标触发告警规则,但未达到配置的持续时间(
for),暂时不推送,用于过滤瞬时异常。 -
Firing(触发):异常持续时间满足规则条件,正式激活告警,推送至 Alertmanager。
2.4 完整告警生命周期
一个告警从产生到最终处理完成,会经历以下5个阶段:

-
规则加载:Prometheus 启动时或配置重载时加载告警规则文件。
-
规则评估:Prometheus 按照
evaluation_interval(默认 1 分钟)周期性执行告警表达式。 -
状态转换:告警从
Inactive→Pending→Firing→Resolved。 -
告警推送:Prometheus 将
Firing状态的告警推送给 Alertmanager。 -
告警处理:Alertmanager 对告警进行分组、抑制、静默后,通过配置的渠道发送通知。
2.5 Alertmanager 内部处理流水线
Alertmanager接收到Prometheus推送的告警后,会按照严格的顺序进行处理:
接收告警 → 告警去重 → 分组聚合 → 抑制检查 → 静默检查 → 路由匹配 → 模板渲染 → 通知发送
三、Prometheus Server 端:告警规则评估逻辑
这是告警的核心生成阶段,完全由Prometheus Server独立完成。
3.1 告警规则基本结构
[root@Ans-prometheus ~]# cat /data/prometheus-3.12.0/prometheus.yml |grep rules
evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
- "./rules/node_rules.yml" #规则配置文件
# - "second_rules.yml"
[root@Ans-prometheus ~]# cat /data/prometheus-3.12.0/rules/node_rules.yml
groups:
- name: node_alerts
interval: 30s # 该组规则的评估间隔,覆盖全局evaluation_interval
rules:
- alert: HighCPUUsage
expr: 100 - (avg by(instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
for: 5m
labels:
severity: warning
team: infra
annotations:
summary: "Instance {{ $labels.instance }} CPU usage is high"
description: "CPU usage is above 80% for 5 minutes (current value: {{ $value | printf \"%.2f\" }}%)"
runbook_url: "https://wiki.example.com/runbooks/high-cpu-usage"
3.2 核心评估逻辑
Prometheus会周期性地执行所有告警规则中的expr表达式。如果表达式返回任何时间序列,则认为告警条件满足。
关键参数详解
-
expr:告警触发条件,是一个PromQL表达式。这是告警规则的核心。 -
for:告警持续时间。这是最容易被误解的参数!-
❌ 错误理解:"每隔多久检查一次"
-
✅ 正确理解:"告警条件必须连续满足多长时间"才会从Pending变为Firing
-
如果在
for时间内,表达式有一次不返回结果,计时器会完全重置
-
-
labels:附加到告警上的标签,用于Alertmanager的路由、分组和抑制 -
annotations:告警的描述性信息,不会影响告警的唯一性,通常包含摘要、详细描述和处理指南
评估过程详解
以HighCPUUsage规则(for: 5m,evaluation_interval: 1m)为例:
| 时间点 | 表达式结果 | 连续满足次数 | 状态变化 | 动作 |
|---|---|---|---|---|
| 00:00 | 85% (>80) | 1 | Inactive → Pending | 开始计数 |
| 00:01 | 88% (>80) | 2 | Pending | 继续计数 |
| 00:02 | 82% (>80) | 3 | Pending | 继续计数 |
| 00:03 | 78% (≤80) | 0 (重置) | Pending → Inactive | 计数归零 |
| 00:04 | 90% (>80) | 1 | Inactive → Pending | 重新开始计数 |
| 00:05 | 92% (>80) | 2 | Pending | 继续计数 |
| 00:06 | 91% (>80) | 3 | Pending | 继续计数 |
| 00:07 | 89% (>80) | 4 | Pending | 继续计数 |
| 00:08 | 87% (>80) | 5 | Pending → Firing | 立即推送告警 |
| 00:09 | 86% (>80) | 6 | Firing | 不再重复推送(已触发) |
重要结论:在最理想情况下,一个配置了for: 5m的告警,从条件首次满足到实际触发,至少需要5分钟。
3.3 告警状态转换
Prometheus中的每个告警实例(由唯一的标签集标识)都有且只有以下四种状态:
-
Inactive(非活跃):告警条件不满足,系统正常运行
-
Pending(待触发):告警条件已满足,但还未达到
for指定的持续时间 -
Firing(已触发):告警条件连续满足了
for指定的时间,已推送给Alertmanager -
Resolved(已恢复):告警条件不再满足,已发送恢复通知
3.4 告警推送逻辑
-
Prometheus只会将Firing状态的告警推送给Alertmanager
-
推送频率由
evaluation_interval控制,默认每分钟一次 -
当告警条件不再满足时,Prometheus会向Alertmanager发送一个Resolved通知
-
Resolved通知会在告警恢复后,**再等待一个
evaluation_interval**发送,以避免因指标抖动导致的频繁恢复/触发
四、Alertmanager 核心功能详解
4.1 分组机制(Grouping)
分组是Alertmanager最基础也是最重要的降噪手段。它通过group_by标签将具有相同特征的告警合并为一个通知,避免告警风暴。
核心时间参数
| 参数 | 含义 | 推荐值 |
group_wait |
首次告警等待时间,用于收集同组的其他告警后再发送 | 10-30s |
group_interval |
同一组内有新告警加入时,需要等待多久再发送更新后的通知 | 5m |
repeat_interval |
如果告警一直处于Firing状态,每隔多久重复发送一次通知 | 1-4h |
配置示例
route:
group_by: ['alertname', 'cluster', 'service']
group_wait: 30s
group_interval: 5m
repeat_interval: 2h
该配置将按告警名称、集群和服务维度分组:
-
收到第一个告警后,等待30秒收集同组的其他告警
-
30秒后发送第一个包含所有已收集告警的通知
-
如果在5分钟内有新的告警加入该组,会在5分钟后发送更新后的通知
-
如果告警一直未恢复,每2小时重复发送一次通知
4.2 抑制规则(Inhibition)
抑制规则用于定义告警间的依赖关系——当某个"根源告警"触发时,自动抑制其引发的"衍生告警"。这是解决故障雪崩式告警的最有效手段。
配置示例
inhibit_rules:
- source_match:
severity: 'critical'
alertname: 'NodeDown'
target_match:
severity: 'warning'
equal: ['instance']
这条规则的含义是:当某个节点宕机(severity=critical,alertname=NodeDown)时,同一实例上所有severity=warning级别的告警都会被自动抑制。
典型应用场景
-
节点宕机 → 抑制该节点上的所有服务告警(CPU、内存、磁盘、端口等)
-
数据库主节点不可用 → 抑制从节点延迟告警
-
网络设备故障 → 抑制该设备下的所有链路和服务告警
-
Kubernetes集群节点NotReady → 抑制该节点上所有Pod的告警
4.3 静默(Silence)
静默与分组和抑制的核心区别在于:分组和抑制是在配置文件中静态定义的,而静默是通过Alertmanager的Web UI或API动态创建的,适合临时屏蔽场景。
使用场景
-
计划内的服务器升级和维护
-
已知问题正在处理中,暂时不需要重复告警
-
误报告警的临时屏蔽
-
非工作时间的低优先级告警屏蔽
通过API创建静默
curl -X POST http://alertmanager:9093/api/v1/silences \
-H "Content-Type: application/json" \
-d '{
"matchers": [
{"name": "alertname", "value": "DiskFull", "isRegex": false},
{"name": "mountpoint", "value": "/var", "isRegex": false},
{"name": "instance", "value": "server-01.example.com", "isRegex": false}
],
"startsAt": "2024-07-01T08:00:00Z",
"endsAt": "2024-07-02T08:00:00Z",
"createdBy": "ops-team",
"comment": "Scheduled backup operation on /var partition"
}'
4.4 三大机制对比
| 机制 | 配置位置 | 典型用途 | 生效方式 | 生命周期 |
| 分组 | 配置文件 | 合并同类告警,降低通知量 | 静态,需更新配置 | 长期 |
| 抑制 | 配置文件 | 定义告警优先级和依赖关系 | 静态,需更新配置 | 长期 |
| 静默 | Web UI/API | 临时屏蔽(如计划内维护) | 动态,即时生效 | 临时 |
五、Alertmanager 核心配置详解
Alertmanager 配置文件 alertmanager.yml 分为四大核心模块:global、route、receivers、inhibit_rules。
5.1 global 全局配置
定义全局参数,如告警恢复超时、SMTP 配置等。
global:
resolve_timeout: 5m # 告警恢复后,等待多久标记为已解决并推送恢复通知
smtp_smarthost: 'smtp.example.com:587'
smtp_from: 'alertmanager@example.com'
smtp_auth_username: 'alertmanager'
smtp_auth_password: 'password' # 生产环境建议使用环境变量或外部文件
5.2 route 路由配置(核心)
路由是Alertmanager配置中最核心的部分,它采用树形结构实现多级匹配,将不同的告警发送给不同的接收者。
5.2.1 完整配置示例
route:
receiver: 'default-receiver'
group_by: ['alertname', 'datacenter']
group_wait: 30s
group_interval: 5m
repeat_interval: 2h
routes:
# 子路由1:critical级别告警发送给紧急团队
- match:
severity: 'critical'
receiver: 'emergency-team'
continue: false # 匹配成功后不再继续匹配同级其他路由
# 子路由2:warning级别,按服务再分流
- match:
severity: 'warning'
receiver: 'warning-team'
routes: # 二级子路由
- match:
service: 'database'
receiver: 'db-warning'
- match:
service: 'frontend'
receiver: 'frontend-warning'
# 子路由3:使用正则匹配
- match_re:
service: 'payment.*'
receiver: 'finance-team'
continue: true # 继续匹配后续路由,实现告警广播
5.2.2 路由匹配机制
-
匹配顺序:从上到下依次匹配子路由,先匹配到的规则优先生效
-
深度优先:匹配到一个子路由后,会先递归匹配它的所有子路由
-
continue标志:决定当一个告警匹配了当前路由节点后,是否继续在同级(同一父节点下的兄弟路由)中进行后续匹配。-
continue: false(默认值):匹配成功后,立即停止遍历当前父节点下的其他兄弟路由。告警只会被发送给当前匹配到的路由所指定的接收器(以及该路由的祖先节点,如果祖先没有设置 continue)。 -
continue: true:匹配成功后,继续尝试匹配同级后续的兄弟路由。这样一条告警可以同时发送给多个接收器。
-
continue: true 的典型使用场景:当你希望一条告警同时通知多个团队时,例如支付系统的告警需要同时通知运维团队和财务团队。
5.2.3 生产级三级路由结构设计
生产环境建议采用以下分级设计,既能保证关键告警的及时处理,又能实现精细化的告警分发:
根路由 (receiver: default-admin)
├── severity: critical
│ ├── service: database → db-oncall
│ ├── service: frontend → frontend-oncall
│ └── service: backend → backend-oncall
├── severity: warning
│ ├── service: database → db-team
│ ├── service: frontend → frontend-team
│ └── service: backend → backend-team
├── severity: info
│ └── (skip or send to slack channel)
└── (default fallback)
5.3 接收器(Receiver)实战
接收器定义了告警最终通过什么渠道发送给谁。Alertmanager支持多种通知渠道,包括邮件、钉钉、企业微信、Slack、短信、电话和Webhook。
5.3.1 邮件通知配置
global:
resolve_timeout: 5m
smtp_smarthost: 'smtp.example.com:587'
smtp_from: 'alertmanager@example.com'
smtp_auth_username: 'alertmanager@example.com'
smtp_auth_password: 'your-email-password'
smtp_require_tls: true
receivers:
- name: 'email-notify'
email_configs:
- to: 'ops-team@example.com'
send_resolved: true
headers:
Subject: '[{{ .Status | toUpper }}] {{ .GroupLabels.alertname }}'
html: |
<h3>{{ .CommonAnnotations.summary }}</h3>
<p>{{ .CommonAnnotations.description }}</p>
<p>告警时间: {{ (.StartsAt.Add 28800e9).Format "2006-01-02 15:04:05" }}</p>
5.3.2 钉钉通知配置
钉钉是国内企业最常用的通知渠道之一。Alertmanager通过Webhook与钉钉机器人集成。
注意:钉钉Webhook只接受POST请求,GET请求会返回43002错误。
receivers:
- name: 'dingtalk-notify'
webhook_configs:
- url: 'https://oapi.dingtalk.com/robot/send?access_token=your-dingtalk-token'
send_resolved: true
http_config:
tls_config:
insecure_skip_verify: false
为了获得更好的钉钉通知格式,建议使用专门的钉钉告警转发服务,如prometheus-webhook-dingtalk。
5.3.3 企业微信通知配置
企业微信是国内企业广泛使用的办公沟通工具。Alertmanager通过Webhook与企业微信机器人集成。
receivers:
- name: 'wecom-notify'
webhook_configs:
- url: 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=your-wecom-key'
send_resolved: true
http_config:
tls_config:
insecure_skip_verify: false
企业微信机器人支持markdown格式的消息,可以创建更美观的告警通知。
5.3.4 Slack通知配置
receivers:
- name: 'slack-notify'
slack_configs:
- api_url: 'https://hooks.slack.com/services/XXX/YYY/ZZZ'
channel: '#alerts'
title: '[{{ .Status | toUpper }}] {{ .CommonLabels.alertname }}'
text: |
*告警详情*
> 级别: {{ .CommonLabels.severity }}
> 实例: {{ .CommonLabels.instance }}
> 摘要: {{ .CommonAnnotations.summary }}
> 时间: {{ (.StartsAt.Add 28800e9).Format "2006-01-02 15:04:05" }} (UTC+8)
send_resolved: true
5.3.5 Webhook通用集成
Webhook是最灵活的通知方式,可以对接任意自定义告警处理系统,如内部工单系统、短信网关、电话告警系统等。
receivers:
- name: 'webhook-processor'
webhook_configs:
- url: 'http://alert-processor:8080/webhook'
send_resolved: true
http_config:
basic_auth:
username: 'alertmanager'
password: 'secure-password'
tls_config:
ca_file: '/etc/alertmanager/ca.crt'
5.3.6 多接收器组合
Alertmanager支持在一个receiver中配置多个通知渠道,实现告警的多渠道同时发送:
receivers:
- name: 'critical-alerts'
email_configs:
- to: 'oncall@example.com'
webhook_configs:
- url: 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=your-wecom-key'
- url: 'https://oapi.dingtalk.com/robot/send?access_token=your-dingtalk-token'
5.4 inhibit_rules 抑制规则
生产降噪核心。典型场景:主机宕机(源告警)→ 抑制该主机所有容器、端口、服务告警(目标告警)。
inhibit_rules:
- source_match:
severity: 'critical'
alertname: 'NodeDown'
target_match:
severity: 'warning'
equal: ['instance'] # 要求源和目标告警的 instance 标签值相等
六、通知模板(Templating)
Alertmanager使用Go模板引擎定制通知内容,可以极大提升通知的信息密度和可读性。
6.1 企业微信模板示例
首先在Alertmanager配置文件中指定模板路径:
templates:
- '/etc/alertmanager/templates/*.tmpl'
然后创建模板文件wecom.tmpl:
{{ define "wecom.message" }}
{
"msgtype": "markdown",
"markdown": {
"content": "{{ if eq .Status \"firing\" }}<font color=\"#FF0000\">🔴 告警触发</font>{{ else }}<font color=\"#008000\">🟢 告警恢复</font>{{ end }}
**告警名称**: {{ .CommonLabels.alertname }}
**告警级别**: {{ .CommonLabels.severity }}
**告警实例**: {{ .CommonLabels.instance }}
{{ if .CommonLabels.service }}**服务名称**: {{ .CommonLabels.service }}{{ end }}
**告警摘要**: {{ .CommonAnnotations.summary }}
**告警详情**: {{ .CommonAnnotations.description }}
**触发时间**: {{ .StartsAt.Local.Format "2006-01-02 15:04:05" }} (UTC+8)
{{ if eq .Status "resolved" }}
**恢复时间**: {{ .EndsAt.Local.Format "2006-01-02 15:04:05" }} (UTC+8)
{{ end }}
**Grafana主机面板**: [点击跳转](http://10.0.0.42:3000/d/rYdddlPWk/node-exporter-full?orgId=1&from=now-24h&to=now&timezone=browser&var-ds_prometheus=afpljo037x62oa&var-job={{ .CommonLabels.job }}&var-node={{ .CommonLabels.instance }}&refresh=1m)
{{ if .CommonAnnotations.runbook_url }}**处理手册**: [点击打开]({{ .CommonAnnotations.runbook_url }}){{ end }}"
}
}
{{ end }}
{{ define "wecom.critical.message" }}
{
"msgtype": "markdown",
"markdown": {
"content": "<font color=\"#FF0000\">🚨 紧急告警触发 🚨</font>
**告警名称**: {{ .CommonLabels.alertname }}
**告警级别**: <font color=\"#FF0000\">CRITICAL</font>
**告警实例**: {{ .CommonLabels.instance }}
**告警摘要**: {{ .CommonAnnotations.summary }}
**告警详情**: {{ .CommonAnnotations.description }}
**触发时间**: {{ .StartsAt.Local.Format "2006-01-02 15:04:05" }} (UTC+8)
**Grafana主机面板**: [点击跳转](http://10.0.0.42:3000/d/rYdddlPWk/node-exporter-full?orgId=1&from=now-24h&to=now&timezone=browser&var-ds_prometheus=afpljo037x62oa&var-job={{ .CommonLabels.job }}&var-node={{ .CommonLabels.instance }}&refresh=1m)
**请立即处理!**
@all"
}
}
{{ end }}
最后在接收器中引用这个模板:
receivers:
- name: 'wecom-notify'
webhook_configs:
- url: 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=your-wecom-key'
send_resolved: true
body: '{{ template "wecom.message" . }}'
6.2 email模板示例
[root@Ans-prometheus /data/alertmanager-0.32.2]# cat templates/email.tmpl
{{/* ========== 邮件主题模板 ========== */}}
{{ define "email.default.subject" -}}
{{- if eq .Status "resolved" -}}[✅已恢复]{{- else -}}[🚨告警中]{{- end -}}
[{{ .CommonLabels.severity | toUpper }}]
{{ .CommonLabels.alertname }} @ {{ .CommonLabels.instance }}
{{- end }}
{{/* ========== 邮件正文模板 ========== */}}
{{ define "email.default.html" }}
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ template "email.default.subject" . }}</title>
<style>
body, table, td, p, div {
margin: 0;
padding: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Microsoft YaHei", sans-serif;
font-size: 14px;
line-height: 1.6;
color: #1e293b;
}
body {
background-color: #f1f5f9;
padding: 20px 0;
}
.container {
max-width: 680px;
margin: 0 auto;
background: #ffffff;
border-radius: 16px;
box-shadow: 0 20px 60px rgba(0,0,0,0.08);
overflow: hidden;
}
.header {
padding: 28px 32px;
text-align: center;
font-size: 20px;
font-weight: 700;
letter-spacing: 0.5px;
color: #fff;
}
.header-critical { background: linear-gradient(135deg, #dc2626, #b91c1c); }
.header-warning { background: linear-gradient(135deg, #f59e0b, #d97706); }
.header-info { background: linear-gradient(135deg, #6366f1, #4f46e5); }
.header-resolved { background: linear-gradient(135deg, #22c55e, #16a34a); }
.header .badge {
display: inline-block;
background: rgba(255,255,255,0.2);
padding: 2px 16px;
border-radius: 20px;
font-size: 13px;
font-weight: 500;
margin-left: 12px;
}
.content {
padding: 32px 32px 20px;
}
.section-title {
font-size: 16px;
font-weight: 600;
color: #0f172a;
border-bottom: 2px solid #e2e8f0;
padding-bottom: 10px;
margin-bottom: 20px;
display: flex;
align-items: center;
gap: 8px;
}
.summary-grid {
display: table;
width: 100%;
border-collapse: collapse;
margin-bottom: 28px;
}
.summary-grid td {
padding: 8px 12px 8px 0;
vertical-align: top;
}
.summary-grid .label {
color: #64748b;
font-weight: 500;
width: 100px;
white-space: nowrap;
}
.summary-grid .value {
font-weight: 500;
color: #0f172a;
}
.severity-tag {
display: inline-block;
padding: 2px 14px;
border-radius: 30px;
font-size: 12px;
font-weight: 700;
letter-spacing: 0.3px;
text-transform: uppercase;
}
.sev-critical { background: #fef2f2; color: #dc2626; }
.sev-warning { background: #fffbeb; color: #d97706; }
.sev-info { background: #eef2ff; color: #4f46e5; }
.sev-resolved { background: #f0fdf4; color: #16a34a; }
.alert-card {
background: #f8fafc;
border-radius: 12px;
padding: 18px 24px;
margin-bottom: 16px;
border-left: 5px solid #94a3b8;
}
.alert-card-critical { border-left-color: #dc2626; }
.alert-card-warning { border-left-color: #f59e0b; }
.alert-card-info { border-left-color: #6366f1; }
.alert-card-resolved { border-left-color: #22c55e; }
.alert-title {
font-size: 15px;
font-weight: 600;
color: #0f172a;
margin-bottom: 6px;
}
.alert-desc {
background: #ffffff;
padding: 10px 14px;
border-radius: 6px;
border: 1px solid #e2e8f0;
margin: 6px 0 10px;
color: #1e293b;
font-size: 13px;
}
.alert-desc .value-highlight {
font-weight: 700;
color: #dc2626;
}
.alert-labels {
font-size: 12px;
color: #64748b;
margin-top: 4px;
word-break: break-all;
}
.alert-labels code {
background: #e9edf2;
padding: 1px 6px;
border-radius: 3px;
font-size: 12px;
color: #1e293b;
}
.runbook-link {
display: inline-block;
margin-top: 8px;
background: #e9edf2;
padding: 4px 14px;
border-radius: 30px;
font-size: 13px;
color: #1e293b;
text-decoration: none;
font-weight: 500;
}
.btn-group {
margin: 24px 0 10px;
display: flex;
flex-wrap: wrap;
gap: 12px;
}
.btn {
display: inline-block;
padding: 10px 24px;
border-radius: 40px;
font-weight: 600;
font-size: 14px;
text-decoration: none;
background: #f1f5f9;
color: #1e293b;
border: 1px solid #e2e8f0;
}
.btn-primary {
background: #1f2937;
color: #fff;
border: none;
}
.btn-primary:hover {
background: #374151;
}
.footer {
text-align: center;
padding: 20px 32px;
font-size: 12px;
color: #94a3b8;
border-top: 1px solid #e2e8f0;
background: #fafcff;
}
@media only screen and (max-width: 640px) {
.container { border-radius: 0; }
.header { font-size: 18px; padding: 20px; }
.content { padding: 20px; }
.summary-grid td { display: block; padding: 4px 0; }
.summary-grid .label { width: auto; }
.alert-card { padding: 14px 16px; }
.btn-group { flex-direction: column; }
.btn { text-align: center; }
}
</style>
</head>
<body>
<div class="container">
<!-- ====== 头部 ====== -->
{{ if eq .Status "resolved" }}
<div class="header header-resolved">
✅ 告警已全部恢复
<span class="badge">恢复时间 {{ (index .Alerts 0).EndsAt.Local.Format "15:04:05" }}</span>
</div>
{{ else }}
{{ $sev := .CommonLabels.severity }}
{{ if eq $sev "critical" }}
<div class="header header-critical">🚨 紧急告警</div>
{{ else if eq $sev "warning" }}
<div class="header header-warning">⚠️ 警告通知</div>
{{ else }}
<div class="header header-info">📢 信息通知</div>
{{ end }}
{{ end }}
<!-- ====== 正文 ====== -->
<div class="content">
<!-- ===== 1. 告警概览(表格,唯一信息源) ===== -->
<div class="section-title">📊 告警概览</div>
<table class="summary-grid">
<tr><td class="label">告警名称</td><td class="value">{{ .CommonLabels.alertname }}</td></tr>
<tr><td class="label">故障实例</td><td class="value">{{ .CommonLabels.instance }}</td></tr>
<tr>
<td class="label">严重级别</td>
<td class="value">
{{ $sev := .CommonLabels.severity }}
{{ if eq $sev "critical" }}
<span class="severity-tag sev-critical">CRITICAL</span>
{{ else if eq $sev "warning" }}
<span class="severity-tag sev-warning">WARNING</span>
{{ else }}
<span class="severity-tag sev-info">INFO</span>
{{ end }}
</td>
</tr>
{{ if eq .Status "firing" }}
<tr>
<td class="label">触发时间</td>
<td class="value">{{ (index .Alerts 0).StartsAt.Local.Format "2006-01-02 15:04:05" }}</td>
</tr>
{{ else }}
<tr>
<td class="label">恢复时间</td>
<td class="value">{{ (index .Alerts 0).EndsAt.Local.Format "2006-01-02 15:04:05" }}</td>
</tr>
{{ end }}
</table>
<!-- ===== 2. 触发告警详情(精简版,无重复信息) ===== -->
{{ if .Alerts.Firing }}
<div class="section-title">🔥 触发告警详情 {{ .Alerts.Firing | len }} 条)</div>
{{ range .Alerts.Firing }}
{{ $sev := .Labels.severity }}
{{ $alertClass := "info" }}
{{ if eq $sev "critical" }}{{ $alertClass = "critical" }}{{ else if eq $sev "warning" }}{{ $alertClass = "warning" }}{{ end }}
<div class="alert-card alert-card-{{ $alertClass }}">
<!-- 标题:节点 + 告警摘要 -->
<div class="alert-title">
{{ if .Annotations.summary }}{{ .Annotations.summary }}{{ else }}{{ .Labels.alertname }}{{ end }}
</div>
<!-- 详细描述 -->
<div class="alert-desc">
{{ .Annotations.description }}
{{ if .Annotations.value }}
<br><span style="font-weight:600;">当前值:</span><span class="value-highlight">{{ .Annotations.value }}</span>
{{ end }}
</div>
<!-- 处理手册按钮 -->
{{ if .Annotations.runbook_url }}
<a href="{{ .Annotations.runbook_url }}" class="runbook-link" target="_blank">📖 查看处理手册</a>
{{ end }}
<!-- 标签信息(紧凑单行) -->
<div class="alert-labels">
<strong>标签信息:</strong>
{{ range $i, $pair := .Labels.SortedPairs }}
{{- if gt $i 0 }} {{ end -}}
<code>{{ $pair.Name }}</code> = {{ $pair.Value }}
{{- end }}
</div>
</div>
{{ end }}
{{ end }}
<!-- ===== 3. 已恢复告警详情(精简版) ===== -->
{{ if .Alerts.Resolved }}
<div class="section-title">✅ 已恢复告警({{ .Alerts.Resolved | len }} 条)</div>
{{ range .Alerts.Resolved }}
<div class="alert-card alert-card-resolved">
<div class="alert-title">
{{ if .Annotations.summary }}{{ .Annotations.summary }}{{ else }}{{ .Labels.alertname }}{{ end }}
</div>
<div class="alert-desc">
{{ .Annotations.description }}
{{ if .Annotations.value }}
<br><span style="font-weight:600;">恢复前值:</span><span class="value-highlight">{{ .Annotations.value }}</span>
{{ end }}
</div>
<div class="alert-labels">
<strong>标签信息:</strong>
{{ range $i, $pair := .Labels.SortedPairs }}
{{- if gt $i 0 }} {{ end -}}
<code>{{ $pair.Name }}</code> = {{ $pair.Value }}
{{- end }}
</div>
</div>
{{ end }}
{{ end }}
<!-- ===== 4. 操作按钮 ===== -->
<div class="btn-group">
{{ if .Alerts.Firing }}
{{ $alert := index .Alerts.Firing 0 }}
{{ $baseUrl := "http://10.0.0.42:3000/d/rYdddlPWk/node-exporter-full" }}
{{ $ds := "afpljo037x62oa" }}
{{ $job := "Node-Exporter" }}
{{ if $alert.Labels.job }}{{ $job = $alert.Labels.job }}{{ end }}
{{ $node := $alert.Labels.instance }}
{{ $grafanaUrl := printf "%s?orgId=1&from=now-24h&to=now&timezone=browser&var-ds_prometheus=%s&var-job=%s&var-node=%s&refresh=1m" $baseUrl $ds $job $node }}
<a href="{{ $grafanaUrl }}" class="btn btn-primary" target="_blank">📊 定位该节点(Grafana)</a>
{{ else }}
{{ $alert := index .Alerts.Resolved 0 }}
{{ if $alert }}
{{ $baseUrl := "http://10.0.0.42:3000/d/rYdddlPWk/node-exporter-full" }}
{{ $ds := "afpljo037x62oa" }}
{{ $job := "Node-Exporter" }}
{{ if $alert.Labels.job }}{{ $job = $alert.Labels.job }}{{ end }}
{{ $node := $alert.Labels.instance }}
{{ $grafanaUrl := printf "%s?orgId=1&from=now-24h&to=now&timezone=browser&var-ds_prometheus=%s&var-job=%s&var-node=%s&refresh=1m" $baseUrl $ds $job $node }}
<a href="{{ $grafanaUrl }}" class="btn btn-primary" target="_blank" style="background:#6b7280;border-color:#6b7280;">📊 查看恢复节点数据(Grafana)</a>
{{ end }}
{{ end }}
</div>
</div>
<!-- ====== 页脚 ====== -->
<div class="footer">
<p>此邮件由 Prometheus + Alertmanager 自动发出,请勿直接回复</p>
<p style="margin-top:4px; opacity:0.7;">如有疑问请联系运维团队</p>
</div>
</div>
</body>
</html>
{{ end }}
接收器中引用这个模板:
# 告警接收器配置
receivers:
- name: "email-alerts"
# 邮件通知:发送给值班人员和经理
email_configs:
- to: "xxx" # 接收人邮箱
send_resolved: true
# 调用 HTML 正文模板
html: '{{ template "email.default.html" . }}'
headers:
Subject: |-
{{- if eq .Status "resolved" }}[✅ 已恢复]
{{- else if eq .CommonLabels.severity "critical" }}[🚨 紧急告警]
{{- else if eq .CommonLabels.severity "warning" }}[⚠️ 警告通知]
{{- else }}[📢 信息通知]
{{- end -}}
{{ .CommonLabels.alertname }} - {{ .CommonLabels.instance }}
6.3 模板常用数据结构
| 变量 | 类型 | 说明 |
.Status |
string | 告警状态,firing或resolved |
.Alerts |
[]Alert | 当前分组中的所有告警 |
.Alerts.Firing |
[]Alert | 当前分组中处于firing状态的告警 |
.Alerts.Resolved |
[]Alert | 当前分组中处于resolved状态的告警 |
.CommonLabels |
map | 所有告警共有的标签 |
.CommonAnnotations |
map | 所有告警共有的注解 |
.GroupLabels |
map | 分组所使用的标签 |
.ExternalURL |
string | Alertmanager的外部访问地址 |
.StartsAt |
time.Time | 告警首次触发的时间(UTC) |
.EndsAt |
time.Time | 告警恢复的时间(UTC) |
七、生产级二进制部署 + Systemd托管
采用二进制部署方式,轻量无依赖,搭配systemd实现开机自启和崩溃重启,是生产环境的首选部署方案。
7.1 下载安装
Alertmanager 0.27.0是当前最新的稳定版本(截至2024年7月):
# 下载最新稳定版
wget https://github.com/prometheus/alertmanager/releases/download/v0.27.0/alertmanager-0.27.0.linux-amd64.tar.gz
# 解压部署
tar -zxvf alertmanager-0.27.0.linux-amd64.tar.gz
cd alertmanager-0.27.0.linux-amd64
# 复制二进制文件到系统目录
cp alertmanager /usr/local/bin/
cp amtool /usr/local/bin/
# 赋予执行权限
chmod +x /usr/local/bin/alertmanager /usr/local/bin/amtool
7.2 创建目录与用户
# 创建专用用户
useradd -M -s /sbin/nologin alertmanager
# 创建配置和数据目录
mkdir -p /etc/alertmanager /var/lib/alertmanager /etc/alertmanager/templates
# 设置目录权限
chown -R alertmanager:alertmanager /etc/alertmanager /var/lib/alertmanager
7.3 生产完整配置文件
创建/etc/alertmanager/alertmanager.yml:
global:
# 告警恢复后等待5分钟再发送恢复通知,避免指标抖动导致的频繁恢复/触发
resolve_timeout: 5m
# QQ邮箱SMTP配置(注意:smtp_auth_password需使用QQ邮箱授权码,非登录密码)
smtp_from: "xxx@qq.com"
smtp_smarthost: "smtp.qq.com:465"
smtp_auth_username: "xxx@qq.com"
smtp_auth_password: "your-qq-authorization-code"
smtp_require_tls: true
smtp_hello: "alertmanager.example.com" # 增加SMTP握手标识,提高邮件送达率
# 告警模板文件路径(确保目录存在且Alertmanager有读取权限)
templates:
- "/data/alertmanager/templates/*.tmpl"
# 根路由配置(所有告警从这里进入)
route:
# 默认接收器:所有未匹配到子路由的告警都发送到默认企业微信群
receiver: "default-wecom"
# 全局分组策略:按告警级别、名称、实例分组,精准区分不同告警
group_by: ["severity", "alertname", "instance"]
# 首次告警等待10秒,收集同组内的其他告警后批量发送
group_wait: 10s
# 同组内有新告警加入时,等待5分钟再发送更新后的通知
group_interval: 5m
# 普通告警持续未恢复时,每2小时重复发送一次
repeat_interval: 2h
# 子路由列表(从上到下匹配,先匹配到的优先生效)
routes:
# 1. 严重级别告警:最高优先级,缩短重复间隔
- match:
severity: "critical"
receiver: "critical-alerts"
repeat_interval: 30m # 严重告警30分钟重复一次
continue: false # 匹配成功后不再继续匹配后续路由
# 2. 数据库服务告警:单独路由给DBA团队
- match:
service: "database"
receiver: "dba-alerts"
continue: true # 数据库告警同时发送给DBA和运维团队
# 3. 运维团队通用告警
- match:
team: "operations"
receiver: "operations-team"
continue: false
# 告警接收器配置
receivers:
# 默认接收器:普通告警发送到运维大群
- name: "default-wecom"
# 企业微信群机器人Webhook(修复93000错误:替换为真实机器人key)
webhook_configs:
- url: "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=REPLACE_WITH_YOUR_REAL_DEFAULT_KEY"
send_resolved: true
body: '{{ template "wecom.message" . }}'
http_config:
tls_config:
insecure_skip_verify: false
# 严重告警接收器:同时发送邮件、钉钉、企业微信紧急群并@所有人
- name: "critical-alerts"
# 邮件通知:发送给值班人员和经理
email_configs:
- to: "oncall@example.com,manager@example.com"
send_resolved: true
headers:
Subject: "[紧急告警] {{ .CommonLabels.alertname }} - {{ .CommonLabels.instance }}"
From: "监控告警中心 <xxx@qq.com>"
# 钉钉通知:发送到紧急告警群
webhook_configs:
- url: "http://localhost:8070/dingtalk/critical/send"
send_resolved: true
# 企业微信紧急群机器人
- url: "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=REPLACE_WITH_YOUR_REAL_CRITICAL_KEY"
send_resolved: true
body: '{{ template "wecom.critical.message" . }}'
# 企业微信原生应用通知:推送到企业微信客户端
wechat_configs:
- corp_id: "ww5421dksajhdasjkhj" # 企业ID
agent_id: "1000002" # 应用ID
api_secret: "your-wechat-api-secret" # 应用密钥
to_party: "2" # 接收部门ID
to_user: "@all" # @部门所有人
send_resolved: true
# DBA团队接收器:数据库相关告警
- name: "dba-alerts"
# 邮件通知
email_configs:
- to: "dba-team@example.com"
send_resolved: true
headers:
Subject: "[数据库告警] {{ .CommonLabels.alertname }}"
# 钉钉通知
webhook_configs:
- url: "http://localhost:8070/dingtalk/db/send"
send_resolved: true
# 企业微信DBA群机器人
- url: "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=REPLACE_WITH_YOUR_REAL_DBA_KEY"
send_resolved: true
body: '{{ template "wecom.message" . }}'
# 运维团队接收器
- name: "operations-team"
email_configs:
- to: "ops-team@example.com"
send_resolved: true
headers:
Subject: "[运维告警] {{ .CommonLabels.alertname }}"
webhook_configs:
- url: "http://localhost:8070/dingtalk/ops/send"
send_resolved: true
# 告警抑制规则(解决故障雪崩问题)
inhibit_rules:
# 规则1:当节点宕机时,抑制该节点上的所有Warning级别告警
- source_match:
severity: "critical"
alertname: "NodeDown"
target_match:
severity: "warning"
equal: ["instance"] # 只有相同实例的告警才会被抑制
# 规则2:当Kubernetes节点不可用时,抑制该节点上的所有Pod告警
- source_match:
severity: "critical"
alertname: "KubeNodeNotReady"
target_match:
severity: "warning"
equal: ["node"]
# 规则3:当数据库主节点不可用时,抑制从节点的延迟告警
- source_match:
severity: "critical"
alertname: "MysqlMasterDown"
target_match:
alertname: "MysqlSlaveDelay"
equal: ["cluster"]
7.4 Systemd服务托管
创建/etc/systemd/system/alertmanager.service:
[Unit]
Description=Prometheus Alertmanager
Documentation=https://prometheus.io/docs/alerting/latest/alertmanager/
After=network.target
[Service]
Type=simple
User=alertmanager
Group=alertmanager
ExecStart=/usr/local/bin/alertmanager \
--config.file=/etc/alertmanager/alertmanager.yml \
--storage.path=/var/lib/alertmanager \
--web.listen-address=:9093 \
--cluster.listen-address=:9094 \
--log.level=info
Restart=on-failure
RestartSec=5
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
7.5 启动并开机自启
# 重新加载systemd配置
systemctl daemon-reload
# 设置开机自启
systemctl enable alertmanager
# 启动服务
systemctl start alertmanager
# 查看服务状态
systemctl status alertmanager
7.6 访问验证
浏览器访问:http://服务器IP:9093,进入Alertmanager可视化后台,可查看当前告警、静默记录、路由状态和集群信息。
八、Prometheus关联Alertmanager配置
修改Prometheus主配置文件prometheus.yml,添加Alertmanager配置:
# 关联告警组件
alerting:
alertmanagers:
- static_configs:
- targets:
- 127.0.0.1:9093
# 如果是集群部署,添加所有实例地址
# - alertmanager-1:9093
# - alertmanager-2:9093
# 加载自定义告警规则文件
rule_files:
- "rules/*.yml"
重载Prometheus配置:
curl -X POST http://prometheus-ip:9090/-/reload
九、高可用(High Availability)
9.1 为什么需要高可用?
单个Alertmanager实例存在单点故障风险。如果Alertmanager宕机,所有告警都将无法发送,这在生产环境中是不可接受的。
9.2 HA架构核心设计
Alertmanager集群由多个通过Gossip协议进行通信的实例组成。每个实例:
-
独立从Prometheus服务器接收告警
-
参与对等的Gossip网状网络
-
将状态(静默规则和通知日志)复制到其他集群成员
-
独立处理并发送通知
Gossip协议负责:
-
成员管理:节点发现、健康检查、故障检测
-
状态复制:静默规则、通知日志的跨节点同步
gossip流言算法协议原理分析:
-
1.前提设定: Gossip时周期性的散播消息,把周期限定为1秒;
-
2.被感染节点随机选择K个临近节点(fan-out)散播消息,这里把fan-out设置为3,每次最多往3个节点散播;
-
3.每次散播消息都选择尚未发送过的节点进行散播;
-
4.收到消息的节点不再往发送节点散播,比如A发送给B,那么B进行散播的时候,不在发送A;
-
5.Gossip过程是异步的,这就是说发消息的节点不会关注对方是否收到,即不等待响应,不管对方有没有收到,它都会每隔1秒向周围节点发消息,异步是它的优点,而消息冗余是它的弱点;
Gossip的优劣势:
优点:
- 扩展性:
网络可以允许节点的任意增加和减少,新增加的节点状态最终会与其他节点一致。
- 容错:
网络中任何节点的宕机和重启都不会影响Gossip消息的传播,Gossip协议具有天然的分布式系统容错特性。
- 去中心化:
Gossip协议不要求任何中心节点,所有节点都可以是对等的,任何一个节点无需知道整个网络状况,只要网络是连通的。
换句话说,任意一个节点就可以把消息散播到全网。
- 一致性收敛:
Gossip协议中的消息会以一传十,十传百一样的指数速级速度在网络中快速传播,因此系统状态不一致可以在很快的时间内收敛到一致。
换句话说,消息传播速度达到了logN。
- 简单:
Gossip协议的过程及其简单,实现起来几乎没有太多复杂性。
缺点:
分布式网络中,没有一种完美的解决方案,Gossip协议和其他协议一样,也有一些不可避免的缺陷,主要有是在数据延迟和冗余。
- 消息的延迟:
由于Gossip协议中,节点指挥随机向少数几个节点发送消息,消息最终是通过多个轮次的散播而到达全网的。
因此使用Gossip协议会造成不可避免的消息延迟,不适合用在实时性要求较高的场景下。
- 消息冗余:
Gossip协议规定,节点会定期随机选择周围节点发送消息,而收到消息的节点也会重复该步骤,因此就不可避免存在消息重复发送给同一节点的情况。
造成了消息的冗余,同时也增加收到消息的节点处理的压力,而且由于定期发送,即使收到了消息的节点还会反复收到重复消息,加重了消息的冗余。
Gossip中通信模式
参考
https://github.com/hashicorp/memberlist
在Gossip协议下,网络中两个节点之间有三种通信模式: "PUSH","PULL"和"PUSH/PULL"。
- PUSH:
节点A将数据(key,value,version)及对应的版本号推送给B节点,B节点更新A中比自己新的数据。
- PULL:
A仅将数据key,vaerion推送给B,B将本地比A新的数据Key,value,version推送给A,A更新本地。
- PUSH/PULL:
与PULL类似,只是多了一步,A再将本地比B新的数据推送给B,B则更新本地。
如果把两个节点数据同步一次定义为一个周期,则在一个周期内,PUSH需通信1次,PULL需通信2次,PULL/PUSH则需要三次。
虽然消息数增加了,但从效果来讲,PUSH/PULL最好,理论上一个周期可以使两个节点完全一致,直观上PUSH/PULL的收敛速度也是最快的。
9.3 HA的三个核心原则
Alertmanager的高可用设计基于以下原则:
-
统一视图与管理:可从任意集群成员查看和管理静默规则和告警
-
故障开放(fail open):网络分区期间倾向于发送重复告警,而非遗漏关键告警
-
至少一次交付:保证告警至少被发送一次,符合"故障开放"理念
9.4 集群配置方法
二进制部署方式:
# 实例1
alertmanager --config.file=/etc/alertmanager/alertmanager.yml \
--storage.path=/var/lib/alertmanager \
--cluster.listen-address=0.0.0.0:9094 \
--cluster.peer=10.0.1.101:9094 \
--cluster.peer=10.0.1.102:9094
# 实例2
alertmanager --config.file=/etc/alertmanager/alertmanager.yml \
--storage.path=/var/lib/alertmanager \
--cluster.listen-address=0.0.0.0:9094 \
--cluster.peer=10.0.1.100:9094 \
--cluster.peer=10.0.1.102:9094
# 实例3
alertmanager --config.file=/etc/alertmanager/alertmanager.yml \
--storage.path=/var/lib/alertmanager \
--cluster.listen-address=0.0.0.0:9094 \
--cluster.peer=10.0.1.100:9094 \
--cluster.peer=10.0.1.101:9094
测试gossip方法1:
- 在一个10.0.1.101节点创建静默;
- 在10.0.1.100,10.0.1.102页面上能看到静默的记录;
Kubernetes部署方式(Prometheus Operator):
apiVersion: monitoring.coreos.com/v1
kind: Alertmanager
metadata:
name: main
namespace: monitoring
spec:
replicas: 3
version: v0.27.0
storage:
volumeClaimTemplate:
spec:
resources:
requests:
storage: 10Gi
9.5 Prometheus侧配置
Prometheus的alerting段应配置所有Alertmanager实例的地址:
alerting:
alertmanagers:
- static_configs:
- targets:
- alertmanager-0:9093
- alertmanager-1:9093
- alertmanager-2:9093
Prometheus会将告警发送到所有Alertmanager实例,由集群内部的去重机制保证最终不会重复发送。
十、常用告警规则示例
以下是生产环境中最常用的告警规则,放入Prometheus的rules目录即可生效:
groups:
- name: node_alerts
rules:
# 主机宕机告警
- alert: NodeDown
expr: up{job="node_exporter"} == 0
for: 1m
labels:
severity: critical
annotations:
summary: "节点 {{ $labels.instance }} 服务失联"
description: "节点 {{ $labels.instance }} 已经超过1分钟无法访问,请立即检查"
# CPU使用率过高
- alert: HighCPUUsage
expr: 100 - (avg by(instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 85
for: 5m
labels:
severity: warning
annotations:
summary: "节点 {{ $labels.instance }} CPU使用率过高"
description: "CPU使用率已超过85%,当前值: {{ $value | printf \"%.2f\" }}%"
# 内存使用率过高
- alert: HighMemoryUsage
expr: (1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100 > 85
for: 5m
labels:
severity: warning
annotations:
summary: "节点 {{ $labels.instance }} 内存使用率过高"
description: "内存使用率已超过85%,当前值: {{ $value | printf \"%.2f\" }}%"
# 磁盘使用率过高
- alert: HighDiskUsage
expr: (node_filesystem_avail_bytes / node_filesystem_size_bytes) * 100 < 15
for: 5m
labels:
severity: warning
annotations:
summary: "节点 {{ $labels.instance }} 磁盘使用率过高"
description: "磁盘 {{ $labels.mountpoint }} 使用率已超过85%,当前可用: {{ $value | printf \"%.2f\" }}%"
- name: blackbox_alerts
rules:
# 端点探测失败
- alert: EndpointDown
expr: probe_success == 0
for: 1m
labels:
severity: critical
annotations:
summary: "端点 {{ $labels.instance }} 探测失败"
description: "端点 {{ $labels.instance }} 已经连续1分钟探测失败,请检查服务状态"
十一、常见问题与排错指南
11.1 收不到任何告警
可能原因及解决方案:
-
Prometheus未配置alerting段:检查prometheus.yml中的alerting配置
-
告警规则未加载:在Prometheus UI的"Rules"页面检查规则状态
-
告警处于Pending状态:等待for指定的持续时间
-
网络不通:检查Prometheus到Alertmanager的9093端口是否开放
-
Alertmanager服务未启动:使用
systemctl status alertmanager检查服务状态
11.2 告警轰炸、重复推送过多
可能原因及解决方案:
-
group_by配置不合理:增加更多的分组标签,如alertname、instance、service
-
group_interval和repeat_interval设置过短:调大这两个参数
-
缺少抑制规则:配置合理的抑制规则,屏蔽衍生告警
-
告警规则过于敏感:调大for参数或调整告警阈值
-
HA 集群状态未同步:检查
--cluster.peer和网络连通性(UDP 9094)
11.3 无告警恢复通知
可能原因及解决方案:
-
send_resolved未设置为true:在接收器配置中添加
send_resolved: true -
resolve_timeout设置过长:根据实际场景调整该参数,默认5分钟
-
告警恢复后立即又触发:检查指标是否存在抖动,可适当调大for参数
11.4 静默规则不生效
可能原因及解决方案:
-
标签匹配规则写错:检查静默中的matchers与告警标签是否完全一致
-
静默时间设置错误:检查开始时间和结束时间是否正确
-
静默规则未同步到所有集群节点:检查集群状态和网络连通性
11.5 集群成员失联
可能原因及解决方案:
-
Gossip端口(9094)被防火墙阻断:开放UDP和TCP 9094端口
-
cluster.peer配置错误:检查所有实例的cluster.peer参数
-
主机名解析失败:使用IP地址代替主机名
十二、最佳实践
12.1 告警规则设计
-
合理设置
for:关键业务 1-2 分钟,非关键 5-10 分钟,避免为 0 导致抖动告警。 -
分层告警:
warning(工作时间处理)、critical(立即处理),不同级别不同接收者。 -
完善 annotations:包含问题描述、处理建议、Grafana 链接、文档链接。
12.2 降噪效果度量
建议企业建立“告警治理”流程,定期评估:
-
告警准确率 = 有效告警数 / 总告警数
-
告警压缩率 = 分组聚合前后通知数量比
-
处理及时率 = 关键告警在规定时间内响应的比例
12.3 生产环境部署建议
-
部署3节点Alertmanager集群实现高可用
-
对Alertmanager自身进行监控,关注以下指标:
-
alertmanager_alerts_received_total:接收的告警总数 -
alertmanager_notifications_failed_total:发送失败的通知数 -
alertmanager_silences_active:活跃的静默规则数
-
-
开发、测试、生产环境使用独立的Alertmanager实例
-
配置合理的数据保留时间,默认120小时
12.4 配置管理最佳实践
-
使用版本控制(Git)管理所有配置文件
-
敏感信息(API Key、密码)使用外部文件或环境变量管理
-
配置变更前先在测试环境验证
-
使用
amtool check-config命令检查配置文件语法 -
配置变更后使用热加载方式生效:
curl -X POST http://alertmanager:9093/-/reload
12.5 告警治理最佳实践
-
建立告警分级制度:
-
Critical:紧急问题,需要立即处理(24x7)
-
Warning:重要问题,工作时间内处理
-
Info:一般信息,无需立即处理
-
-
定期清理无效告警规则
-
建立告警响应SLA
-
持续优化告警准确率和压缩率
十三、总结
Alertmanager是Prometheus监控体系中不可或缺的告警管理平台。它通过分组、抑制、静默等机制有效解决了告警风暴问题,通过灵活的路由和模板系统实现了告警的精细化分发和定制化通知。
核心要点回顾:
-
分离式架构:Prometheus负责告警判定,Alertmanager负责告警处理
-
三大核心机制:分组(去重)、抑制(优先级)、静默(临时屏蔽)
-
树形路由:支持多级匹配和continue标志,实现灵活的告警分发
-
多渠道通知:支持邮件、钉钉、企业微信、Slack、Webhook等多种通知方式
-
高可用集群:基于Gossip协议,保证告警不丢失
通过合理配置和使用Alertmanager,可以显著降低告警噪音,帮助运维团队从被动的"告警疲劳"中解放出来,聚焦于真正需要处理的关键问题,提升整个系统的可靠性和可维护性。

浙公网安备 33010602011771号