前言

在建设监控系统的过程中我们最绕不开的问题的就是告警问题。在传统的 AlertManager 方案中,总会遇到许许多多问题,

  • 当我们有多台 Prometheus 但又没有通过 联邦集群 的方式汇聚到同一台 Prometheus 上时,该怎么避免维护多套 Rules
  • 当监控值在告警阈值上下波动,我们又该怎么避免产生恢复信息风暴,无效的信息过多挤刷掉重要的告警信息,监控就失去了作用。
  • 对于正在维护 AlertManager 的小伙伴应该深有体会,为了做告警信息分流,给 Alertmanager 写那一堆 routereceiver ,最后再回过头来看那几百甚至过千行的配置文件,不得不汗颜。
  • Alertmanager 的通知渠道,默认是支持邮件告警的,但如果我们需要将告警信息发送到钉钉或者企业微信,此时又不得不又引入一个 webhook

所以,推荐使用夜莺(Nightingale)来做统一告警管理。夜莺(Nightingale)虽然也集成了监控和展示的功能,但在这里我们只用来做告警引擎,在对接多套时序库时,统一告警规则管理。

AlertManager告警体系中,prometheus周期性执行 Rule,当指标满足 Rule时变为 Pending状态而后变为 Firing状态并发送信息给 AlertManager。与 AlertManager不同的是,夜莺(Nightingale)通过周期性去执行指标命令,当指标满足规则时进行告警。简单点说,夜莺(Nightingale)是主动去查询 Prometheus 随后产生告警信息,而 AlertManagerPrometheus 主动推送过来才产生告警信息。

1740396181055.png

项目地址:

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 ,配置需要告警的数据源
1740396214351.png

2. 告警媒介配置

2.1 配置SMTP服务器

告警通知 --> 通知设置 --> SMTP设置

以163邮箱为例

Host = "smtp.163.com"
Port = 25
User = "邮箱账号"
Pass = "邮箱密码"
From = "邮箱账号"
From_Name = "监控平台"
InsecureSkipVerify = true
Batch = 5

2.2 配置用户告警媒介

人员组织 --> 用户管理 --> 编辑 ,配置接收告警信息的邮箱及钉钉/企业微信机器人
1740396374742.png

3. 告警规则配置

告警管理 --> 告警规则 --> Default Busi Group --> 新增

1740396453526.png

1740396469166.png

1740396483175.png

1740396493230.png

  • 规则名称: 磁盘使用率告警 , 规则名称自定义发送告警会用到这个名称
  • 数据源类型: 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 }} 磁盘使用率为

4. 屏蔽规则配置

AlertManager 静默功能类似,针对某个标签进行屏蔽,在指定时间段即使产生告警也不发送告警信息。当我们的操作会触发告警但我们又不希望发出告警信息时,可通过该功能进行屏蔽,比如我们接下来需要重启服务器、又或者每天凌晨需要重启某个服务,屏蔽规则可以帮我们减少不必要的打扰。

告警管理 --> 屏蔽规则 --> Default Busi Group --> 新增

1740396542583.png

1740396551870.png

1740396566223.png

配置说明:屏蔽每天凌晨1点到1点30分时产生的所有包含 hostname标签值为的 “测试服务器” 的告警事件

4. 通知模板优化

4.1 邮箱告警模板优化

默认通知模板如下:

1740396597990.png

优化后的通知模板如下:

1740396736179.png

1740397127306.png

  • 模板文件
    告警通知 --> 通知模板 --> 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}}
  • 效果如下
    1740397165431.png

写在最后

在我们建设监控体系的过程,夜莺(Nightingale)是我们一个不错的选择方案。夜莺(Nightingale)产生的所有告警信息都会写入到 MySQL 数据库中,也方便我们日后使用脚本进行统计从而输出监控周报/月报。

文章作者: hzbb
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 运维小记
Prometheus 自动化 Nightingale
喜欢就支持一下吧
打赏
微信 微信
支付宝 支付宝