1. 从零开始认识PrometheusAlert与飞书告警如果你正在做运维或者负责一个线上系统的稳定性那你肯定对“半夜被电话叫醒处理故障”这件事深恶痛绝。告警信息如果只是躺在监控系统里那它的价值就大打折扣了。真正的价值在于它能第一时间、以最合适的方式通知到对的人。这就是我们今天要聊的PrometheusAlert一个能把来自Prometheus、Zabbix、Grafana等各种监控系统的告警消息转发到你熟悉的办公协作工具——比如飞书——上的“消息中转站”。简单来说PrometheusAlert就像一个万能翻译官和快递员。监控系统比如Prometheus用它们自己的“语言”通常是Webhook JSON发出告警而我们的开发、运维同学日常沟通都在飞书上。两边语言不通信息就无法传递。PrometheusAlert的作用就是1. 听懂监控系统的告警语言2. 把它翻译成飞书机器人能理解的格式3. 打包好通过飞书提供的接口把告警卡片精准地“快递”到指定的群聊或个人。这样一来你不需要时刻盯着监控大盘告警会自动找到你而且是以结构清晰、信息完整、甚至可以直接操作比如跳转到故障链接的富文本卡片形式出现。那么为什么是飞书飞书的群机器人功能非常强大它支持交互式消息卡片这让告警信息不再是冷冰冰的文字。我们可以通过配置模板让告警卡片根据严重程度显示不同的颜色如红色代表紧急绿色代表恢复包含故障主机、服务、时间、描述等关键字段并且可以直接点击链接跳转到Prometheus或Grafana进行详情查看。这极大地缩短了从接收告警到定位问题的路径。很多朋友在初次配置时可能会遇到消息发不出去或者发出去了但格式不对、颜色不生效的问题。别急这通常都是模板配置这个关键环节没打通。接下来我就带你一步步拆解这个模板把配置过程中那些容易踩的“坑”都填平。2. 核心实战飞书告警模板语法全解析配置飞书告警90%的工作量和难点都在于编写那个“模板”。这个模板本质上是一个Go语言的文本模板它定义了如何将Prometheus Alertmanager发过来的那一大串JSON数据转换成一条条人类可读、飞书可识别的消息。听起来有点复杂别怕我们把它拆开揉碎了看。首先你得理解Alertmanager发过来的数据长什么样。上面原始文章里提供了一个非常标准的JSON测试样例这就是模板要处理的“原材料”。我们配置模板就是告诉PrometheusAlert“当你收到这样一坨数据时请按照我写的格式提取里面的字段拼装成最终的消息。”2.1 模板基础结构与变量一个最基本的飞书告警模板核心是处理.alerts这个数组。因为一次告警可能同时触发多条规则所以数据是以数组形式来的。模板里最常见的结构就是使用{{ range $k, $v : .alerts }}来遍历每一条告警信息。这里的$v就代表了单条告警的所有内容。接下来我们看看$v里面有哪些宝贝可以挖$v.status这是最关键的字段之一它的值要么是firing告警触发要么是resolved告警恢复。飞书机器人正是根据这个字段的值来决定消息卡片标题部分的颜色很多同学配置后卡片没有颜色八成就是因为模板里没有把这个字段传递出去或者传递的格式不对。$v.labels这是一个键值对集合包含了告警规则定义时附带的标签比如alertname告警名称、instance故障实例地址、job任务名、severity严重级别注意原始样例里拼写是serverity这是个常见的typo你的实际数据可能不同等。在模板中访问方式如{{$v.labels.alertname}}。$v.annotations这也是键值对通常存放更详细的描述信息比如description详细描述、summary摘要。这些信息是我们需要展示给接收者的核心内容访问方式如{{$v.annotations.description}}。$v.startsAt和$v.endsAt告警开始时间和结束恢复时间。这里有个超级实用的函数GetCSTtime它是PrometheusAlert内置的专门用来将UTC时间转换成我们东八区的北京时间用法是{{GetCSTtime $v.startsAt}}。没有它你看到的时间会是UTC时间需要自己脑补8小时非常不友好。$v.generatorURL这是一个可以直接点击的链接通常指向触发这条告警的Prometheus查询语句页面对于快速定位问题至关重要。.externalURL这是Alertmanager的外部访问地址通常可以用来构建指向Alertmanager的链接。理解了这些变量你就掌握了模板的“单词”。接下来我们学习如何用“语法”把它们组成“句子”。2.2 条件判断与消息格式化告警消息需要区分“故障”和“恢复”两种状态并且呈现不同的信息。这就需要用到Go模板的{{if}}...{{else}}...{{end}}条件判断语句。原始文章里的模板已经给出了一个经典范式{{if eq $v.status resolved}} 【这里是恢复消息的模板】 {{else}} 【这里是触发告警消息的模板】 {{end}}在飞书消息中我们通常使用Markdown语法来加粗、换行。例如用**文本**表示加粗用\n或直接换行来表示分行。飞书卡片消息支持更丰富的交互式组件但通过机器人发送的普通消息使用Markdown格式化已经能获得很好的效果。例如你可以把告警名称做成链接*[{{$v.labels.alertname}}]({{.externalURL}})*这样点击就能快速跳转。这里我分享一个自己踩过的坑飞书机器人的消息内容中如果包含大段的JSON或特殊字符可能会导致消息发送失败或格式错乱。建议在模板中对于从labels或annotations取出的值使用| safeHtml或| js等模板函数进行转义如果PrometheusAlert支持的话或者确保这些字段内容本身是简洁的。更稳妥的做法是在Prometheus的告警规则定义alert.rules中就规范好summary和description的内容避免放入未经处理的复杂字符串。3. 手把手配置从模板编写到飞书接收理论说了这么多是时候动手了。我们来一步步完成一个比原始文章示例更详细、更健壮的飞书告警模板配置。3.1 第一步准备你的飞书群机器人打开飞书进入你需要接收告警的群聊。点击群设置找到“群机器人”选择“添加机器人”。在机器人列表里选择“自定义机器人”。给机器人起个名字比如“运维告警小助手”并上传一个醒目的头像。最关键的一步在“安全设置”中我强烈建议你选择“自定义关键词”。你可以添加如“告警”、“Prometheus”、“故障”等关键词。这意味着只有消息内容中包含这些词之一时机器人才会发送成功。这是一个非常重要的安全措施可以防止你的Webhook URL被恶意调用刷屏。创建成功后飞书会提供一个Webhook URL格式类似https://open.feishu.cn/open-apis/bot/v2/hook/xxxxxxxxxxxxx。这个URL就是PrometheusAlert将要调用的地址请妥善保管不要泄露。3.2 第二步在PrometheusAlert中配置飞书告警渠道假设你已经部署好了PrometheusAlert部署过程不是本文重点可以参考官方文档它的管理界面通常有一个“告警通道”配置。在告警通道页面选择添加“飞书”类型的通道。通道名称可以填“生产环境飞书告警”。将第一步获取的Webhook URL粘贴到对应配置项。通常还有一个“密钥”或“签名”选项如果你在创建机器人时开启了“签名校验”就需要把签名密钥也填在这里。为了简单起见初次配置可以先只用“自定义关键词”安全设置。保存这个通道配置。记下这个通道的ID或名称后面配置模板时会用到。3.3 第三步编写并调试你的告警模板现在进入核心环节在PrometheusAlert的模板管理页面新建一个模板。模板类型选择“飞书”。下面我给出一个优化后的模板示例它包含了更清晰的格式和更全面的信息{{ $externalURL : .externalURL }} {{ range $index, $alert : .alerts }} {{if eq $alert.status resolved}} **✅ [Prometheus告警恢复]({{$alert.generatorURL}})**\n *告警名称*{{$alert.labels.alertname}}\n *告警级别*{{$alert.labels.severity | default warning}}\n *告警状态*{{$alert.status}}\n *故障主机*{{$alert.labels.instance}}\n *故障服务*{{$alert.labels.application | default N/A}}\n *开始时间*{{GetCSTtime $alert.startsAt}}\n *结束时间*{{GetCSTtime $alert.endsAt}}\n *描述信息*{{$alert.annotations.description}}\n {{else}} ** [Prometheus告警触发]({{$alert.generatorURL}})**\n *告警名称*{{$alert.labels.alertname}}\n *告警级别*{{$alert.labels.severity | default critical}}\n *告警状态*{{$alert.status}}\n *故障主机*{{$alert.labels.instance}}\n *故障服务*{{$alert.labels.application | default N/A}}\n *触发时间*{{GetCSTtime $alert.startsAt}}\n *描述信息*{{$alert.annotations.description}}\n {{if $alert.annotations.runbook_url}} *处理手册*{{$alert.annotations.runbook_url}}\n {{end}} {{end}} --- {{end}}这个模板做了哪些优化状态标识更直观在标题前加了✅和表情让人一眼区分恢复和告警。字段显示更规范每个字段前用*字段名*的格式清晰明了。默认值处理使用了| default N/A这样的模板函数具体函数名需查看你的PrometheusAlert版本支持当severity或application标签不存在时显示一个默认值避免模板渲染出错导致整个消息发送失败。可选字段展示通过{{if $alert.annotations.runbook_url}}判断是否存在处理手册链接如果存在则显示这在实际运维中非常有用。分隔清晰用---分隔多条告警避免信息混在一起。将这段模板内容保存并命名为“飞书通用告警模板”。3.4 第四步关联模板与告警规则最后一步我们需要告诉PrometheusAlert当收到来自某个Prometheus的告警时使用哪个模板发送到哪个飞书通道。在PrometheusAlert的“告警路由”或“转发规则”配置页面新建一条规则。规则匹配这里可以设置匹配条件。例如你可以设置当labels.severity为critical时才触发飞书告警。或者更简单一点先配置一条默认规则匹配所有来自你生产环境Alertmanager的告警。选择模板在规则中选择你刚才创建的“飞书通用告警模板”。选择通道选择你配置的“生产环境飞书告警”通道。保存并启用规则。4. 避坑指南常见问题与排查技巧配置完成后最激动也最紧张的时刻就是测试了。你可能遇到消息发不出去或者发出去了但格式不对的情况。别慌我把自己和同事们踩过的坑都总结在这里。4.1 消息发送失败飞书收不到检查Webhook URL这是最最常见的问题。确认你从飞书复制的Webhook URL完整无误没有多余的空格。可以在浏览器中或使用curl命令尝试访问这个URL如果返回{code:19001,msg:param invalid for token}之类的错误说明URL本身是有效的但缺少参数或参数错误。如果返回404那URL可能就是错的。检查安全设置如果你设置了“自定义关键词”请确保你的告警模板渲染出的最终消息内容里包含了你设定的关键词。比如你设的关键词是“告警”那么模板里一定要有“告警”这两个字。我建议在模板的固定部分如标题加入关键词比如“Prometheus告警”这样最保险。查看PrometheusAlert日志这是定位问题的金钥匙。登录部署PrometheusAlert的服务器查看它的应用日志。日志里会明确记录它是否收到了Alertmanager的请求、模板渲染是否成功、以及调用飞书接口后返回的错误信息。根据错误信息对症下药。检查网络连通性确保PrometheusAlert所在的服务器能够正常访问互联网特别是能访问open.feishu.cn这个域名。4.2 消息能收到但格式错乱或颜色不生效颜色不生效飞书消息卡片的颜色依赖于消息中是否包含“告警”、“报警”等特定关键词以及消息的整体格式。但根据我的实测和原始文章的提示最关键的是确保{{$v.status}}这个变量被正确输出到了消息内容中。飞书的后端会解析这个消息并根据status的值是firing还是resolved来赋予标题栏不同的颜色通常是红/绿。请仔细检查你的模板确保告警状态{{.status}}或类似字段被包含在最终输出的文本里。Markdown格式无效飞书机器人对Markdown的支持是有限的并且有自己的一套解析规则。避免使用过于复杂或嵌套的Markdown语法。确保你的换行使用的是\n在Go模板字符串中或者直接在模板中换行。有时候在PrometheusAlert的Web界面配置模板时换行符会被吃掉导致所有内容挤在一行。如果遇到这种情况可以尝试在模板中使用\n显式换行。时间格式不对如果你看到的时间不是北京时间请确认你正确使用了{{GetCSTtime .startsAt}}函数。这个函数是PrometheusAlert内置的如果它未生效可能是版本问题可以查阅官方文档确认或者考虑在告警规则中直接处理时间格式。4.3 进阶调试技巧当你对模板做了复杂修改后如何高效调试我常用的方法是使用测试功能PrometheusAlert的Web管理界面通常有一个“测试”功能允许你粘贴一段Alertmanager的JSON数据就像原始文章提供的那种样例然后选择模板进行预览。一定要用好这个功能在保存模板前先预览能避免很多低级错误。简化模板如果复杂模板不工作就把它简化到极致。比如先写一个只输出{{.alerts | len}}条告警的模板测试消息是否能正常发送。然后逐步增加字段每加一个就测试一次这样可以快速定位是哪个字段或语法导致了问题。关注Alertmanager数据模板问题的根源往往是数据不对。确保你的Prometheus告警规则能正确触发并且Alertmanager发送给PrometheusAlert的数据结构符合预期。可以用一个简单的HTTP请求接收工具如netcat或webhook.site临时替换PrometheusAlert的地址抓取一次Alertmanager发过来的原始数据看看里面的labels、annotations字段名是否和你模板中引用的完全一致。比如官方常用severity但你的数据里可能是serverity拼写错误那模板引用severity就会得到空值。配置飞书告警模板就像搭积木也是一门“翻译”的艺术。一开始可能会被各种花括号和变量名绕晕但一旦你成功配置好第一条告警看着它清晰地出现在飞书群里那种成就感会让你觉得这一切都值得。最重要的是这套流程跑通后你的运维响应效率会得到质的提升。再也不用担心重要的告警被淹没在邮件或嘈杂的聊天记录里了。希望这份实战指南能帮你少走弯路如果遇到其他古怪的问题不妨去PrometheusAlert的GitHub仓库看看Issues或者和社区里的同行们交流一下很多时候你遇到的坑别人早就踩过并且填平了。