ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Alertmanager邮件与微信告警实战:路由分组模板避坑指南

Alertmanager邮件与微信告警实战:路由分组模板避坑指南 做监控这块的朋友应该都体会过这种场景Prometheus 抓取指标、配置告警规则都弄好了Alertmanager也部署上去了结果线上真的出故障时告警发没发出去、发到哪、有没有人看反而成了最大的不确定性。我自己早期就吃过亏明明 rule 文件里for: 5m写得清清楚楚Prometheus 的/alerts页面也显示Firing可邮箱里就是收不到邮件手机上也毫无动静。后来排查了一圈才发现问题全出在 Alertmanager 的路由配置和接收器上——规则触发只是上半场下半场怎么把告警准确、及时、不轰炸地送到人手里才是真正见功夫的地方。这篇文章就围绕 Alertmanager 的邮件告警和微信告警两条线展开把配置方法、模板写法、路由分组、常见坑一次讲透。整体偏实操适合已经把 Prometheus 搭起来、正在折腾告警通知的同学如果只是刚接触 Prometheus也可以先照着配一遍遇到概念我再顺带解释不会让你卡在半路。1. 为什么用 Alertmanager 做邮件和微信告警1.1 告警链路里 Alertmanager 到底扮演什么角色先理清一个很多人没彻底搞清楚的问题Prometheus 本身带告警规则比如up 0这种表达式一旦命中Prometheus 会把这个告警标记为pending或firing。但它只是一个状态机真正负责“把告警送出去”的是 Alertmanager。换句话说Prometheus 负责“发现问题”Alertmanager 负责“通知人”。链路大概是这样的Prometheus 根据告警规则计算表达式命中后生成一条告警。Prometheus 通过配置里的alertmanagers地址把告警推送给 Alertmanager。Alertmanager 收到告警后根据route路由树决定这个告警该走哪个receiver。receiver 再调用具体渠道邮件、企业微信、钉钉、webhook 等把内容发出去。所以如果你在 Prometheus 里配了 rule但没配alertmanagers这个字段那 Prometheus 压根不会把告警发出去。这一步往往会漏掉很多人排查半天最后发现 Prometheus 配置文件里alerting那一段压根是空的。在 Alertmanager 这一侧它最核心的三个能力是分组grouping、抑制inhibition、静默silence。这仨功能解决了实际运维里最头疼的问题——告警风暴和重复告警。比如一台数据库挂了往往会连带触发几十条相关告警如果没有分组和抑制你的手机会在十分钟内被几百条消息打成震动模式。Alertmanager 会把同一类告警合并成一条通知然后再用抑制规则把噪音压下去。这一点后面展开讲。1.2 邮件加微信的组合解决什么问题告警渠道的选择本质是在“可靠性”和“触达率”之间做平衡。邮件的好处是链路简单、留痕清晰、适合做事后追溯但缺点是没人保证你盯着收件箱微信准确说是企业微信应用消息的好处是手机端能直接弹出来看一眼就能判断要不要起来处理。所以生产环境里我推荐的做法是两个通道同时开邮件做归档微信做即时触达。微信这块很多人以为能直接把告警推到自己个人微信上。这个我刚才也踩过坑——目前官方可靠的路子不是个人微信而是企业微信应用消息。你可以理解成企业微信提供一个“应用”的入口Alertmanager 通过 webhook 把告警内容交给一个转发脚本脚本再调用企业微信 API 把消息推给应用里指定的人。接收的人手机上不需要装额外的特殊工具只要装了企业微信并加入企业就行推送效果和微信消息几乎一致。这也是为什么网上搜“微信告警”时最后基本都会落到企业微信的方案上。至于 Linux 服务器上想跑企业微信客户端收告警这类操作麒麟系统也常见有人问我建议直接打消这个念头。告警推送的正确姿势是 API 调用不是靠客户端挂在服务器上接收——客户端方案既不稳定也没法做到告警内容的自动化编排。API 推送不管你的服务器是什么发行版只要出网能访问企业微信接口就行这才符合运维自动化的思路。2. 部署与最小可用配置先把告警跑起来2.1 安装部署单二进制还是容器Alertmanager 的部署非常轻量官方给的是一个静态二进制压缩包解压出来就一个可执行文件加一个默认配置文件不像 Prometheus 还要考虑存储和大量 TSDB 参数。单机部署的话直接下载对应平台的包解压后把二进制放到/usr/local/bin/alertmanager再配上 systemd 服务就能跑。我用的是容器方式一个 docker-compose 就能搞定version: 3 services: alertmanager: image: prom/alertmanager:v0.27.0 container_name: alertmanager restart: always ports: - 9093:9093 volumes: - ./alertmanager.yml:/etc/alertmanager/alertmanager.yml - ./template:/etc/alertmanager/template command: - --config.file/etc/alertmanager/alertmanager.yml - --web.external-urlhttp://your-server:9093这里有几个参数值得说下。--web.external-url建议显式配置特别是后面要用 Alertmanager 的 Web UI 做静默操作时回调地址对不对会直接影响体验。如果生产环境有多个副本还可以加--cluster.listen-address和--cluster.peer组成集群实现告警去重和高可用。不过说实话告警通知这种事单节点挂了影响的就是通知不像业务系统那样分秒必争所以单机起步完全够用等真需要了再上集群不迟。启动后浏览器访问http://your-server:9093能看到 Alertmanager 的 Web UI左侧有 Alerts、Silences、Status 几个标签现在基本是空的因为还没有任何告警进来。2.2 alertmanager.yml 核心结构拆解Alertmanager 的配置集中在alertmanager.yml内容不算多但每个字段背后都有讲究。一个最精简的配置长这样global: resolve_timeout: 5m smtp_smarthost: smtp.qq.com:465 smtp_from: senderqq.com smtp_auth_username: senderqq.com smtp_auth_password: 你的SMTP授权码 smtp_require_tls: false route: group_by: [alertname] group_wait: 10s group_interval: 2m repeat_interval: 4h receiver: email receivers: - name: email email_configs: - to: opsexample.com逐段解释一下global是全局配置。邮件相关的 SMTP 参数都放这smtp_smarthost是邮件服务器的地址和端口smtp_from是发件人地址smtp_auth_username和smtp_auth_password是认证信息。注意这里填的不是邮箱登录密码而是 SMTP 授权码。QQ 邮箱、163 邮箱都在网页端设置里开 SMTP 服务后生成授权码直接用登录密码会导致 535 认证失败的报错。smtp_require_tls: false是很多人容易忽略的一点。使用 465 端口时Alertmanager 是直接走 SSL 加密连接的不需要在应用层再协商 STARTTLS所以这里要设成false。如果用 587 端口走 STARTTLS那就保持不变默认就是true。route是路由树Alertmanager 收到告警后会从根路由开始向下匹配决定这个告警交给哪个 receiver、按什么规则分组。最基本的根路由只需配receiver一个字段就能把默认目标指向邮件接收器。receivers是接收器列表每个接收器定义一个发送渠道名字与路由里的receiver对应。上面这个配置所有告警都会以邮件形式发到opsexample.com。2.3 路由与接收人设计思路很多教程到上面就结束了但真实场景里一个 receiver 是不现实的。你的团队里数据库告警应该发给 DBA业务接口告警发给后端组基础设施宕机告警发给所有人。这种按角色分发的需求就要靠路由树的多分支来实现了。我常用的设计思路是根路由做默认兜底子路由按标签分流。比如route: group_by: [alertname, instance] group_wait: 30s group_interval: 5m repeat_interval: 4h receiver: default-email routes: - match: team: db receiver: dba-email continue: false - match_re: severity: critical|emergency receiver: all-page continue: true - match: team: web receiver: web-wechat逻辑很直白如果告警带上了teamdb标签就交给 DBA 的邮件接收器如果级别是critical同时发给 all-page这个接收器可以同时配邮件和企业微信如果teamweb就走微信通道。continue字段控制的是匹配到当前子路由后是继续往下匹配还是直接结束。比如 critical 告警我想让所有人知道就设continue: true这样它还能继续命中后面的teamweb规则。这种设计思路的要点是尽量用 Prometheus 告警规则里已有的标签作为分流依据比如team、severity、env。标签体系一开始就要规划好不然后面接线全靠告警规则里写死改起来坡度很大。3. 邮件告警配置详解从 SMTP 到 HTML 模板3.1 SMTP 配置与授权码邮件通道是 Alertmanager 最基础、最稳定的接收方式也最适合做告警的“底账”。SMTP 这块具体配置我在上一节已经给了一个例子这里再补几个不同邮件服务商的差异。如果你用的是 QQ 邮箱smtp_smarthost: smtp.qq.com:465 smtp_from: your-nameqq.com smtp_auth_username: your-nameqq.com smtp_auth_password: xxxxxxxxxxxxxxxx # 授权码16位 smtp_require_tls: false如果是 163 邮箱把smtp_smarthost改成smtp.163.com:465授权码也是单独生成的。企业邮箱的话如阿里云企业邮箱一般是smtp.mxhichina.com:465认证方式一样只是端口和地址不同。有个小提示如果公司内部有邮件中继比如 Postfix 或 Exchange且允许内网匿名发信那 SMTP 认证段可以留空smtp_smarthost填内网地址就行速度比走公网邮箱快很多也不受授权码过期影响。配完之后可以用amtool快速验证配置是否合法amtool check-config alertmanager.yml如果输出SUCCESS说明基础结构没问题。但这一步验证不了邮件能否真实送达最好直接触发一条测试告警跑一遍全流程。3.2 用模板做出可读性强的邮件正文Alertmanager 默认的邮件内容比较简陋标题是[FIRING:1] (alertname)正文是一系列Labels和Annotations的键值对。给内部自己人看凑合能用但如果要发给业务方或者老板最好自定义一个 HTML 模板。配置模板需在alertmanager.yml里声明模板目录templates: - /etc/alertmanager/template/*.tmpl然后在 template 目录下建一个email.tmpl我用的模板供参考{{ define email.html }} html body h3Prometheus 告警通知/h3 {{ range .Alerts }} table border1 cellpadding5 styleborder-collapse:collapse;font-family:Arial; trtd告警状态/tdtd{{ .Status }}/td/tr trtd告警名称/tdtd{{ .Labels.alertname }}/td/tr trtd严重级别/tdtd{{ .Labels.severity }}/td/tr trtd实例/tdtd{{ .Labels.instance }}/td/tr trtd触发时间/tdtd{{ .StartsAt.Format 2006-01-02 15:04:05 }}/td/tr trtd描述/tdtd{{ .Annotations.summary }}/td/tr /table {{ end }} /body /html {{ end }}这里有个非常容易踩坑的地方Go 模板的时间格式化参考时间是固定的2006-01-02 15:04:05这不是随便写的字符串而是 Go 语言里格式化时间的一种约定。如果你写YYYY-MM-DD HH:mm:ss渲染出来会是满满的YYYY原始字符串不会自动转成真实时间。邮件接收器配置里引用这个模板receivers: - name: email email_configs: - to: opsexample.com headers: subject: {{ template email.subject . }} html: {{ template email.html . }}如果模板渲染出错Alertmanager 会在日志里打印详细的错误信息。特别是字段名大小写写错比如把startsAt写成StartAt模板引擎会直接渲染失败然后在告警日志里报template: ... map has no entry for key。这块调试起来不算麻烦先把手工构造的 JSON 灌进amtool template render就能单独验证模板后面 6.2 节我会专门说 amtool 的用法。3.3 邮件告警的几个坑邮件渠道最典型的收不到问题优先级排序大概是SMTP 认证失败、模板渲染失败、被邮箱服务商扔进垃圾箱、foxmail 等客户端本地归档。第一类报错在 Alertmanager 日志里能看到比如535 Error: authentication failed这是授权码不对或者没开 SMTP。第二类通常日志里有template execution failed不会影响发送但邮件可能是空的。第三类很隐蔽特别是用企业邮箱测试时邮件可能根本没进收件箱而是被当成营销邮件丢进了垃圾箱。排查方法就是让对方在网页版邮箱里搜索发件人地址如果能在垃圾箱里找到说明你需要在邮件服务商后台把自己的发件地址加白名单。第四类涉及到 foxmail 这类客户端。foxmail 新版本把邮件存储路径从原来的Foxmail 7.2/Storage改成了带账号目录的 Accounts 结构不少人以为邮件丢了其实只是没更新客户端或者本地索引出问题导致旧邮件显示不出来。真实排查时先登录网页版邮箱确认邮件是否真的送达如果网页版有而本地 foxmail 没有那就是客户端同步的问题不要再回头折腾 Alertmanager 了。4. 微信告警配置实战企业微信应用消息的完整接入4.1 为什么不是个人微信而是企业微信这个问题几乎每次分享都会有人问。原因很简单个人微信的消息推送接口不开放给普通开发者你没法拿个人微信号作为告警推送的接收端去调用 API。企业微信则不同它提供了完整的应用消息推送接口而且触达体验和微信基本一致手机上的企业微信 App 会弹出通知即便没打开 App 也能收到推送。所以整体方案是Alertmanager 配置一个webhook类型 receiver收到告警后把内容 POST 到一个本地转发服务。转发服务可以是一个几十行代码的小脚本也可以是现成的开源组件拿到告警内容后请求企业微信接口获取access_token然后把消息推给指定的企业成员。你可能看到网上有些人直接用现成的开源项目比如prometheus-webhook-wechat。这类项目确实省事但优点是现成的缺点是黑盒出了告警内容格式不满意你还得去改人家的 Go 代码。我更推荐自己写一个几十行的转发脚本逻辑完全可控出了问题也能第一时间定位。下面都是基于自写转发脚本来讲的。4.2 创建企业微信应用与获取凭证首先你得有一个企业微信账号。注册很简单用手机号就能搞定不一定要有真实企业资质。登录企业微信管理后台之后按下面的步骤创建应用在左侧菜单找到“应用管理”点击“自建”区的“创建应用”。填写应用名称比如“监控告警”、上传 Logo、选择可见范围。可见范围这一步很关键——只有在该范围内的成员手机端企业微信才能收到这个应用的消息推送。创建成功后在应用详情页能看到两个关键参数AgentId和Secret。还有一个全局参数企业ID。在“我的企业 → 企业信息”页面底部能看到一串由字母和数字组成的企业 IDCorpID。使用这些参数时用下面这个接口换取 access_tokencurl -s https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid你的企业IDcorpsecret你的Secret返回结果里access_token字段就是最终凭证有效期是 7200 秒2 小时过期后需要重新获取。所以转发脚本里一定要做 token 缓存否则告警高峰时每个 CD 间隔都去请求一次 token很容易触发企业微信接口频率限制。这里还要提醒一个很现实的问题企业微信新版 API 在某些情况下要求配置可信 IP。如果调用接口时返回类似60020的报错多半就是这个原因。处理方法是拿告警推送服务器所在的公网 IP去企业微信管理后台“应用详情 → 企业可信 IP”里配置一下。如果是自己在家里测试出口 IP 不固定那这个限制可能让你折腾一阵子。4.3 用 Webhook 接收器转发告警到企业微信Alertmanager 配置一个 webhook 接收器就相当于“把告警投递给本地的 HTTP 接口”receivers: - name: wechat-webhook webhook_configs: - url: http://127.0.0.1:8080/wechat send_resolved: truesend_resolved: true表示恢复通知也一并推送到微信。这个开关建议打开不然你只收到“出问题”的消息收不到“已恢复”的消息值守的人会一直带着疑问等着。每一条告警对值班同事来说都意味着“要不要现在处理”有了恢复通知状态闭环才完整。下面这个 Python 脚本我放在/opt/alertmanager-wechat/webhook.py用 Flask 起一个最轻量的 HTTP 服务import time import requests from flask import Flask, request, jsonify APP Flask(__name__) CORP_ID 你的企业ID SECRET 你的应用Secret AGENT_ID 你的应用AgentId TO_USER all # 也可以指定成员userid如zhangsan|lisi TOKEN_CACHE {token: , expire: 0} def get_token(): now time.time() if TOKEN_CACHE[token] and TOKEN_CACHE[expire] now 60: return TOKEN_CACHE[token] url https://qyapi.weixin.qq.com/cgi-bin/gettoken params {corpid: CORP_ID, corpsecret: SECRET} resp requests.get(url, paramsparams, timeout10).json() if resp.get(errcode) ! 0: raise Exception(fget token failed: {resp}) TOKEN_CACHE[token] resp[access_token] TOKEN_CACHE[expire] now resp[expires_in] return TOKEN_CACHE[token] def send_wechat(text): token get_token() url fhttps://qyapi.weixin.qq.com/cgi-bin/message/send?access_token{token} payload { touser: TO_USER, msgtype: markdown, agentid: AGENT_ID, markdown: {content: text}, safe: 0, } resp requests.post(url, jsonpayload, timeout10).json() if resp.get(errcode) ! 0: raise Exception(fsend message failed: {resp}) def format_alert(alert): labels alert.get(labels, {}) annotations alert.get(annotations, {}) status alert.get(status, firing) time_str time.strftime(%Y-%m-%d %H:%M:%S, time.localtime(alert.get(startsAt, 0))) title 【告警恢复】 if status resolved else 【告警触发】 content f{title} font color\warning\{labels.get(alertname, unknown)}/font\n content f 级别: {labels.get(severity, unknown)}\n content f 实例: {labels.get(instance, unknown)}\n content f 时间: {time_str}\n if annotations.get(summary): content f 描述: {annotations[summary]}\n return content APP.route(/wechat, methods[POST]) def webhook(): data request.json for alert in data.get(alerts, []): text format_alert(alert) send_wechat(text) return jsonify({status: ok}) if __name__ __main__: APP.run(host0.0.0.0, port8080)企业微信的 markdown 消息支持部分格式比如表示引用块、font colorwarning可以给文字上色。实际推送到企业微信后效果比纯文本好看很多。这个脚本里TO_USER可以设为all发给全部可见范围成员也可以指定多个成员的 userid用竖线分隔。成员 userid 在“通讯录 → 成员详情”里能看到不是微信号别搞混。这块我建议用nohup或者 systemd 常驻后台跑。systemd 的 unit 文件很简单[Unit] DescriptionAlertmanager Wechat Webhook Afternetwork-online.target [Service] ExecStart/usr/bin/python3 /opt/alertmanager-wechat/webhook.py Restartalways RestartSec5 [Install] WantedBymulti-user.target脚本跑起来后先在本地验证一下接口能用curl -XPOST http://127.0.0.1:8080/wechat -d {alerts:[{status:firing,labels:{alertname:test,severity:warning,instance:localhost:9090},annotations:{summary:这是一条测试告警},startsAt:2025-01-01T10:00:0008:00}]}如果企业微信正常收到推送说明整条链路已经通了一半。剩下的一半是验证 Alertmanager 到 webhook 的对接可以用 amtool 或者直接往 Alertmanager 的 API 里灌一条测试告警。4.4 微信模板消息的进阶写法上面的示例里消息内容是直接在 Python 里拼接的。如果告警信息字段很多、团队协作时希望不同级别显示不同样式建议把内容渲染的逻辑单独抽出来做成一个模板文件而不是天天改脚本代码。企业微信 markdown 支持的颜色标签有info灰色、comment绿色、warning橙红色三种。我通常这样设计info级别告警用info颜色只发到邮件不进微信。warning级别告警用warning颜色微信推送。critical级别告警用warning颜色并且加一个所有人的提示。企业微信的 markdown 消息不支持真正的 所有人 语法但可以在文案里显式写“请相关同事立即处理”。如果想在消息里附上 Alertmanager 的告警链接可以在format_alert里拼一个 urlcontent f [查看告警详情](http://your-alertmanager:9093/#/alerts?receiverwechat-webhook)\n企业微信中这个链接可以直接点击跳转值班人员不用再单开电脑查监控这是一个很实用的细节。5. 告警路由、分组与抑制别让告警轰炸你5.1 分组参数group_wait、group_interval、repeat_interval告警通知最大的敌人不是发不出去而是发得太多。网络上有一个经典梗凌晨三点值班同学被 200 条企业微信消息炸醒手忙脚乱打开电脑发现只是某个非核心服务重启闪断了片刻。避免这种惨剧靠的就是 Alertmanager 的分组机制。先看分组配置route: group_by: [alertname, instance] group_wait: 30s group_interval: 5m repeat_interval: 4hgroup_by决定了告警按哪些标签归类。比如group_by: [alertname, instance]意味着同一个实例上同一类告警会合并成一条通知而如果只按alertname分组那不同实例上的同一类告警也会合成一条适合全局组件挂掉导致大规模故障的场景。选哪种看实际需求——我自己的习惯是基础设施告警按alertname分组业务告警按alertname instance分组这样既能看到“哪些模块出了问题”也能精确定位到具体实例。group_wait指同一分组的第一条告警到达后Waiting 多长时间再发通知。这个时间是为了收集同组内可能陆续到达的其他告警一起打包发出去避免一条条推送。设 30s 是一个比较平衡的值既不会等太久也能聚合大多数相关告警。group_interval指同一分组后续有新告警加入时间隔多久再次通知。5 分钟是常用配置太短容易频繁打扰太长可能会导致问题升级时得不到及时通知。repeat_interval指同一组告警在未恢复时隔多久重复发送一次通知。4 小时是常见选择设太短比如 1 小时会变成另一种骚扰设太长比如 24 小时会导致有些问题被遗忘。5.2 抑制规则与静默的实战用法抑制规则解决的是“主故障导致的一堆连带告警”。最常见的例子数据库服务器宕机了除了node_down这种根因告警还有十几个数据表连接失败、API 超时的衍生告警。这时候如果全部推送值班人员收到的 90% 是噪音。Alertmanager 的抑制规则可以这么写inhibit_rules: - source_matchers: - severity critical - alertname NodeDown target_matchers: - severity ~ warning|info equal: - instance这段规则的含义是如果某个instance上有NodeDown级别为critical的告警在触发那么同一instance上所有warning和info级别的告警都会被抑制。用大白话说就是——机器都挂了还在乎它上面的进程状态干嘛。这条规则的威力巨大配置后告警量能下降 70% 以上。但注意equal字段一定要把instance写进去否则会误伤其他正常实例上的告警导致真正的故障被掩盖。静默Silence则是人主动沉默告警的操作。比如你计划今晚凌晨 2 点对某台机器做维护期间用 docker stop 重启容器一定会触发告警但你不想被打扰。在 Alertmanager 的 Web UI 里找到对应告警点 Silences → New Silence填上匹配标签、时长、原因保存后这段时间内符合条件的告警就不会通知了。用命令行的方式更高效amtool silence add --alertmanager.urlhttp://localhost:9093 \ --duration1h \ --commentplanned maintenance \ alertnameNodeDown instance10.0.0.1:9100这里也提醒一下静默一定要带--comment写明原因。没有原因标注的静默在多人协作时等于埋了一颗雷。5.3 路由表匹配优先级与 continue 关键字路由树的匹配规则除了上一节提到的match和match_re还有一个容易被忽略的continue。它的语义是当前路由匹配成功后是否继续尝试匹配兄弟路由。举个例子我想让所有critical级别告警不仅发给对应团队同时抄送一份到管理层值守群。这时候可以这样写route: receiver: default routes: - match: severity: critical receiver: page-oncall continue: true - match: team: db receiver: dba-wechat当一条severitycritical, teamdb的告警到达时会先匹配到第一条子路由发给 oncall 组因为continue: true它不会立即终止还会继续匹配第二条子路由再发给 DBA 的微信。如果不加continue则匹配到第一条后直接返回DBA 反而收不到告警。这种“多通道并行通知”在很多运维团队里都是刚需。路由匹配顺序是从上到下子路由之间是兄弟平级关系不满足匹配条件就跳过。还有一个细节根路由不写routes只有receiver和分组参数时它是所有告警的兜底入口。务必保证根路由有一个合理的默认 receiver不然未命中任何子路由的告警会石沉大海。6. 常见问题排查与调试技巧实录6.1 告警没发出去怎么查我在帮别人排查 Alertmanager 问题时发现 80% 的问题是出在上游而不是下游。所以遇到“邮件/微信没收到”我的排查顺序是这样第一步先在 Prometheus Web UI 的/alerts页面看告警状态。如果状态是pending说明还没有达到for的阈值时间如果一直pending不转firing看看是不是for设得太长如果根本没有这个告警说明告警规则表达式本身就没触发。这一步可以确认“Prometheus 到底有没有产生告警”。第二步确认 Prometheus 是否把告警推送给了 Alertmanager。检查 Prometheus 配置文件里alerting段落alerting: alertmanagers: - static_configs: - targets: [localhost:9093]缺了这段Prometheus 根本不会发送告警给 Alertmanager。这一步是新手最容易漏的。第三步去 Alertmanager Web UI 的 Alerts 页面看有没有告警进来。如果 Prometheus 显示firing但 Alertmanager 页面空白基本可以断定是推送连接出了问题看一下 Prometheus 日志里有没有alertmanager notification failed之类的信息。第四步检查 Alertmanager 自己的日志。告警发送失败时日志会明确写出错误比如 SMTP 认证失败、webhook POST 超时、模板渲染错误。先看日志不要瞎猜。6.2 amtool 这个命令行的正确用法amtool 是 Alertmanager 官方自带的命令行工具但很多人部署时根本没在意过它。它在排查问题时极其好用尤其是调用 API 测试。检查配置amtool check-config alertmanager.yml查询当前活跃告警amtool alert query --alertmanager.urlhttp://localhost:9093添加一个静默amtool silence add --alertmanager.urlhttp://localhost:9093 \ --duration30m --comment测试静默 alertnameTestAlert但最实用的功能可能是模板渲染。定义好.tmpl文件后可以用一条构造好的 JSON 灌进去直接看到模板输出不用真的等告警触发echo {alerts:[{status:firing,labels:{alertname:Test,severity:warning,instance:host1},annotations:{summary:test summary},startsAt:2025-01-01T10:00:0008:00}]} | \ amtool template render --template.glob/etc/alertmanager/template/*.tmpl \ --template.text{{ template email.html . }}这样就能在本地肉眼检查模板渲染结果再也不用发真实告警去试了效率提升不止一个档次。6.3 高可用部署与数据保留提示Alertmanager 的高可用部署不算复杂多个实例通过--cluster.listen-address和--cluster.peer组成集群实例之间会通过 gossip 协议同步告警状态避免重复发送。以两节点为例节点 A 启动参数alertmanager --config.filealertmanager.yml \ --cluster.listen-address192.168.1.10:9094 \ --cluster.peer192.168.1.11:9094节点 B 启动参数alertmanager --config.filealertmanager.yml \ --cluster.listen-address192.168.1.11:9094 \ --cluster.peer192.168.1.10:9094然后在 Prometheus 的alerting配置里把两个地址都写上Prometheus 会同时推送告警给两个实例。由于集群内已有去重机制任意一个节点通知了另一个节点就不会重复发。这套方案虽然不难但要注意一个坑集群模式下如果两个节点的--config.file内容不一致分组成员和路由行为可能产生诡异差异所以一定要使用配置管理工具统一分发alertmanager.yml。顺便说一件事Alertmanager不存储告警历史它只是转发。如果你想事后统计“过去一个月告警触发多少次”靠 Alertmanager 是查不到的得用 Prometheus 的ALERTS这个指标在 Prometheus 里做查询。这也是很多人在做告警报表时踩坑的地方。告警记录建议沉到 Prometheus 的 TSDB 里统一管理。关于数据保留Prometheus 默认保留 15 天如果你需要做月度告警趋势分析记得在启动参数里调整--storage.tsdb.retention.time。不过那是另一个话题了这里点到为止。7. 最后再分享一个实用小技巧用 Alertmanager 一年多我最深的体会是告警配置的核心不是怎么发出去而是怎么让人愿意看。很多人一开始收到几条告警还认真看等被垃圾告警轰炸几天后就会把所有通知静音真正的故障反而没人管。所以我的建议是第一周宁可少配告警也要把分组、抑制、路由的规则打磨清楚每种告警推出去之前自己先以值班人的身份问一句——“我看到这条消息知道该怎么处理吗”如果答案是否定的这条告警的通知文案还得再改。最后再分享一个小技巧测试企业微信告警时不要每次都用反序列化脚本手工构造数据。我习惯在 Alertmanager 上添加两个测试用的静默——一个匹配所有alertnameTestAlert的告警时长 1 小时另一个不用加。这样你想验证时直接往 Prometheus 加一条临时 rule触发告警后真实走完整个链路测完删掉 rule 和静默即可。整个流程差不多 2 分钟比任何 mock 数据都可靠。告警通知这件事多测几次、踩过几次坑才能真正在半夜被真实告警叫醒时不慌不忙地翻个身拿出手机看上一眼然后做个正确的判断。
返回列表