告警管理平台,一次性解决告警中心化/降噪/分流/模板问题
前言
在建设监控系统的过程中我们最绕不开的问题的就是告警问题。在传统的 AlertManager
方案中,总会遇到许许多多问题,
- 当我们有多台
Prometheus
但又没有通过联邦集群
的方式汇聚到同一台Prometheus
上时,该怎么避免维护多套Rules
。 - 当监控值在告警阈值上下波动,我们又该怎么避免产生恢复信息风暴,无效的信息过多挤刷掉重要的告警信息,监控就失去了作用。
- 对于正在维护
AlertManager
的小伙伴应该深有体会,为了做告警信息分流,给Alertmanager
写那一堆route
和receiver
,最后再回过头来看那几百甚至过千行的配置文件,不得不汗颜。 Alertmanager
的通知渠道,默认是支持邮件告警的,但如果我们需要将告警信息发送到钉钉或者企业微信,此时又不得不又引入一个webhook
。
所以,推荐使用夜莺(Nightingale)来做统一告警管理。夜莺(Nightingale)虽然也集成了监控和展示的功能,但在这里我们只用来做告警引擎,在对接多套时序库时,统一告警规则管理。
在 AlertManager
告警体系中,prometheus
周期性执行 Rule
,当指标满足 Rule
时变为 Pending
状态而后变为 Firing
状态并发送信息给 AlertManager
。与 AlertManager
不同的是,夜莺(Nightingale)通过周期性去执行指标命令,当指标满足规则时进行告警。简单点说,夜莺(Nightingale)是主动去查询 Prometheus
随后产生告警信息,而 AlertManager
是 Prometheus
主动推送过来才产生告警信息。
项目地址:
https://github.com/ccfos/nightingale
我们只使用它的告警管理功能,社区版本就能满足我们的需求,对于有更加复杂功能需求比如排班、认领以及需要更多数据源的支持可使用它的企业版本 -- Flashduty
1. 夜莺(Nightingale)一键部署
git clone https://github.com/Public-Compose/n9e.git
cd n9e
docker-conpose up -d
需已安装docker及docker-compose环境,镜像已改用阿里源,无需魔法
容器启动后平台登录地址为:http://{ip}:17000
,默认账号:root
默认密码:root.2020
1.2 添加 Prometheus 数据源
集成中心
--> 数据源
--> 新增
--> Prometheus Like
,配置需要告警的数据源
2. 告警媒介配置
2.1 配置SMTP服务器
告警通知
--> 通知设置
--> SMTP设置
以163邮箱为例
Host = "smtp.163.com"
Port = 25
User = "邮箱账号"
Pass = "邮箱密码"
From = "邮箱账号"
From_Name = "监控平台"
InsecureSkipVerify = true
Batch = 5
2.2 配置用户告警媒介
人员组织
--> 用户管理
--> 编辑
,配置接收告警信息的邮箱及钉钉/企业微信机器人
3. 告警规则配置
告警管理
--> 告警规则
--> Default Busi Group
--> 新增
- 规则名称: 磁盘使用率告警 , 规则名称自定义发送告警会用到这个名称
- 数据源类型: prometheus
- 告警条件:
ceil(100 - (node_filesystem_avail_bytes{fstype=~"ext4|xfs"}/node_filesystem_size_bytes{fstype=~"ext4|xfs", mountpoint !~"/var.*", mountpoint !~"/boot.*"} )*100) >= 80
- 告警级别: 三级告警 ,针对不同的阈值设置不同的等级
- 执行频率:60s,每60s执行一次指标查询
- 持续时长:240s,240s内每次查询都符合指标随即发送告警
- 通知媒介:dingtalk、wecom、email
- 告警接收组:demo-root-group
- 启用恢复通知
- 留观时长(秒):180 ,180s内每次查询都不符合指标随即发送恢复信息
- 重复通知间隔(分钟):10080 ,该告警一直未恢复时,7天后会再次发送告警信息
- 最大发送次数:3 , 一直未恢复的告警重复发送次数
- 附加信息: 附加告警
恢复值
及告警内容
- recovery_promql:
ceil(100 - (node_filesystem_avail_bytes{fstype=~"ext4|xfs", hostname="{{ $labels.hostname}}", device="{{ $labels.device }}"}/node_filesystem_size_bytes{fstype=~"ext4|xfs", mountpoint !~"/var.*", mountpoint !~"/boot.*"} )*100)
- summary: 当前
{{ $labels.device }}
磁盘使用率为
- recovery_promql:
4. 屏蔽规则配置
与 AlertManager
静默功能类似,针对某个标签进行屏蔽,在指定时间段即使产生告警也不发送告警信息。当我们的操作会触发告警但我们又不希望发出告警信息时,可通过该功能进行屏蔽,比如我们接下来需要重启服务器、又或者每天凌晨需要重启某个服务,屏蔽规则可以帮我们减少不必要的打扰。
告警管理
--> 屏蔽规则
--> Default Busi Group
--> 新增
配置说明:屏蔽每天凌晨1点到1点30分时产生的所有包含 hostname
标签值为的 “测试服务器” 的告警事件
4. 通知模板优化
4.1 邮箱告警模板优化
默认通知模板如下:
优化后的通知模板如下:
- 模板文件
告警通知
-->通知模板
-->email
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>夜莺告警通知</title>
<style type="text/css">
.wrapper {
background-color: #f8f8f8;
padding: 15px;
height: 100%;
}
.main {
width: 600px;
padding: 30px;
margin: 0 auto;
background-color: #fff;
font-size: 12px;
font-family: verdana,'Microsoft YaHei',Consolas,'Deja Vu Sans Mono','Bitstream Vera Sans Mono';
}
header {
border-radius: 2px 2px 0 0;
}
header .title {
font-size: 14px;
color: #333333;
margin: 0;
}
header .sub-desc {
color: #333;
font-size: 14px;
margin-top: 6px;
margin-bottom: 0;
}
hr {
margin: 20px 0;
height: 0;
border: none;
border-top: 1px solid #e5e5e5;
}
em {
font-weight: 600;
}
table {
margin: 20px 0;
width: 100%;
}
table tbody tr{
font-weight: 200;
font-size: 12px;
color: #666;
height: 32px;
}
.succ {
background-color: green;
color: #fff;
}
.fail {
background-color: red;
color: #fff;
}
.succ th, .succ td, .fail th, .fail td {
color: #fff;
}
table tbody tr th {
width: 80px;
text-align: right;
}
.text-right {
text-align: right;
}
.body {
margin-top: 24px;
}
.body-text {
color: #666666;
-webkit-font-smoothing: antialiased;
}
.body-extra {
-webkit-font-smoothing: antialiased;
}
.body-extra.text-right a {
text-decoration: none;
color: #333;
}
.body-extra.text-right a:hover {
color: #666;
}
.button {
width: 200px;
height: 50px;
margin-top: 20px;
text-align: center;
border-radius: 2px;
background: #2D77EE;
line-height: 50px;
font-size: 20px;
color: #FFFFFF;
cursor: pointer;
}
.button:hover {
background: rgb(25, 115, 255);
border-color: rgb(25, 115, 255);
color: #fff;
}
footer {
margin-top: 10px;
text-align: right;
}
.footer-logo {
text-align: right;
}
.footer-logo-image {
width: 108px;
height: 27px;
margin-right: 10px;
}
.copyright {
margin-top: 10px;
font-size: 12px;
text-align: right;
color: #999;
-webkit-font-smoothing: antialiased;
}
</style>
</head>
<body>
<div class="wrapper">
<div class="main">
<header>
<!-- <h3 class="title">{{.RuleName}}</h3>-->
<h3 class="title">{{if .IsRecovered}}<font color="#008800">💚 {{.RuleName}}恢复</font>{{else}}<font color="#FF0000">💔 {{.RuleName}}告警</font>{{end}}</h3>
<p class="sub-desc"></p>
</header>
<hr>
<div class="body">
<table cellspacing="0" cellpadding="0" border="0">
<tbody>
{{if .IsRecovered}}
<tr class="succ">
<th>级别状态:</th>
<td>S{{.Severity}}</td>
</tr>
{{else}}
<tr class="fail">
<th>级别状态:</th>
<td>S{{.Severity}}</td>
</tr>
{{end}}
{{if .TargetNote}}
<tr>
<th>设备备注:</th>
<td>{{.TargetNote}}</td>
</tr>
{{end}}
{{if .TargetIdent}}
<tr>
<th>监控对象:</th>
<td>{{.TargetIdent}}</td>
</tr>
{{end}}
{{if eq (index .TagsMap "job") "linux"}}
<tr>
<th>所在区域:</th>
<td>{{index .TagsMap "position"}}</td>
</tr>
<tr>
<th>环境类型:</th>
<td>{{index .TagsMap "env"}}</td>
</tr>
<tr>
<th>主机名称:</th>
<td>{{index .TagsMap "hostname"}}</td>
</tr>
<tr>
<th>主机IP:</th>
<td>{{index .TagsMap "instance"}}</td>
</tr>
{{end}}
{{if .IsRecovered}}
<tr>
<th>恢复内容:</th>
<td>{{.AnnotationsJSON.summary}} {{formatDecimal .AnnotationsJSON.recovery_value 0}}%</td>
</tr>
<tr>
<th>触发时间:</th>
<td>
{{timeformat .TriggerTime}}
</td>
</tr>
<tr>
<th>恢复时间:</th>
<td>{{timeformat .LastEvalTime}}</td>
</tr>
{{else}}
<tr>
<th>告警内容:</th>
<td>{{.AnnotationsJSON.summary}} {{.TriggerValue}}% </td>
</tr>
<tr>
<th>触发时间:</th>
<td>
{{timeformat .TriggerTime}}
</td>
</tr>
{{end}}
</tbody>
</table>
<hr>
<footer>
<div class="copyright" style="font-style: italic">
XX运维中心,为系统稳定保驾护航!
</div>
</footer>
</div>
</div>
</div>
</body>
</html>
{{if .IsRecovered}}
判断告警状态为告警
or恢复
{{index .TagsMap "hostname"}}
获取告警事件中hostname
标签的值{{if eq (index .TagsMap "job") "linux"}}
判断告警类型,如果告警事件中job
标签的值为linux
则使用这个模板。告警的类型有多种,可能是服务器资源告警、微服务状态告警、站点监控告警,不同的告警类型最终要发送的告警信息模板也会有些区别。比如运行在K8S
中的微服务告警模板可能需要包含Namespace
以及所在的node
,在一些大型集群中可以快速判断。
4.2 邮箱标题告警模板优化
- 模板文件
告警通知
-->通知模板
-->mailsubject
{{if .IsRecovered}}Recovered:{{index .TagsMap "name"}} 当前已恢复正常!{{else}}Triggered:{{index .TagsMap "name"}} 当前无法访问!{{end}}{{else}}{{if .IsRecovered}}Recovered{{else}}Triggered{{end}}:{{.RuleName}}{{.TagsJSON}}{{end}}
- 效果如下
写在最后
在我们建设监控体系的过程,夜莺(Nightingale)是我们一个不错的选择方案。夜莺(Nightingale)产生的所有告警信息都会写入到 MySQL
数据库中,也方便我们日后使用脚本进行统计从而输出监控周报/月报。