为什么要 Alertmanager?
prometheus本身不支持告警功能,主要通过插件alertmanage来实现告警。AlertManager用于接收Prometheus发送的告警并对于告警进行一系列的处理后发送给指定的用户。
prometheus触发一条告警的过程:
prometheus--->触发阈值--->超出持续时间--->alertmanager--->分组|抑制|静默--->媒体类型--->邮件|钉钉|微信 |webhook 等。
Prometheus 生态中的警报是在 Prometheus Server 中计算警报规则(Alert Rule)并产生的,而所谓计算警报规则,其实就是周期性地执行一段 PromQL,得到的查询结果就是警报,比如:
node_load5 > 20
这个 PromQL 会查出所有”在最近一次采样中,5分钟平均 Load 大于 20”的时间序列。这些序列带上它们的标签就被转化为警报。
具体查询语句参考: https://prometheus.io/docs/prometheus/latest/querying/basics/
只是,当 Prometheus Server 计算出一些警报后,它自己并没有能力将这些警报通知出去,只能将警报推给 Alertmanager,由 Alertmanager 进行发送。
这个切分,一方面是出于单一职责的考虑,让 Prometheus “do one thing and do it well”, 另一方面则是因为警报发送确实不是一件”简单”的事,需要一个专门的系统来做好它。可以这么说,Alertmanager 的目标不是简单地”发出警报”,而是”发出高质量的警报”。
安装AlertManager
安装AlertManger的方式和安装Prometheus、NodeExporter的方式一样,下载运行就行。
./alertmanager --config.file=alertmanager.yml
可以添加--config.file
选项来指定配置文件,创建systemd的步骤其他的一模一样。
web ui查看 : http://alertmanager_ip:9093
在Prometheus设置报警规则
把 prometheus 和 alertmanager 关联。
在prometheus.yml中设置匹配报警规则的间隔和规则文件:
alerting:
alertmanagers: # 配置alertmanager
- static_configs:
- targets:
- 127.0.0.1:9093 #alertmanager服务器ip端口
rule_files: # 告警规则文件
- 'rules/*.yml'
rules文件的模板如下:
ALERT
IF
[ FOR ]
[ LABELS ]
[ ANNOTATIONS ]
比如:
groups:
- name: Memory
- alert: NodeMemoryUsage
expr: (node_memory_MemTotal_bytes - (node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_momory_Cached_bytes)) / ndoe_momory_MemTotal_bytes * 100 > 90
for: 1m
labels:
severity: High
annotations:
summary: "{{$labels.instance}}:内存使用率太高。"
description: "{{$lables.instance}}: 内存使用率已经达到{{ $value }},高于90%。"
这里就定义了一个NodeMemoryUsage
的报警规则,一条报警规则由以下几个部分组成:
- alert: 告警规则的名称,不需要是唯一的。
- expr:基于PromQL表达式的告警触发条件。
- for:评估等待时间,表示只有当触发条件持续一段时间后才发送告警,在等到发送的过程中报警的状态为
pending
。可选参数。 - labels:自定义标签,指定额外的标签附加在告警上。
- annotations: 一般用于告警信息的展示。
这里面的for
字段会影响到我们告警的到达时间,这个参数主要用于降噪,有些指标是有抖动的,通过指定Pending Duration
可以过滤掉这些瞬时抖动。所以有的情况下计算我们的监控图表上面已经有部分指标达到了告警的阈值了,但是并不一定会触发告警规则,比如我们上面的规则中,设置的是1分钟的 Pending Duration
,如果持续时间太短,没有达到一分钟,就不会报警。
一般情况下我们在规则文件的annotations中使用summary
描述告警的概要信息(标题),description
用来描述告警的详细信息(正文)。AlertManger的UI会根据这两个标签来显示告警信息,同时Prometheus也支持模板化label和annotations。
groups:
- name: example
rules:
- alert: InstanceDown
expr: up == 0
for: 5m
labels:
severity: High
annotations:
summary: "{{ $labels.instance }}挂了"
description: "{{ $labels.instance }}已经有挂了五分钟了。"
- alert: HighRequest
expr: api_http_request_latancies_second{quantile="0.5"} > 1
for: 10m
annotations:
summary: " {{ $labels.instance }}处理延迟太高"
description: "{{ $labels.instance }}的平均处理延迟时间超过1秒。"
promtool 工具检查语法
$ ./promtool check rules rules/node.yml
Checking rules/node.yml
SUCCESS: 7 rules found
检查所有:
$ ./promtool check config conf/prometheus.yml
Checking conf/prometheus.yml
SUCCESS: 2 rule files found
Checking /opt/prometheus/rules/node.yml
SUCCESS: 8 rules found
Checking /opt/prometheus/rules/ssl_expiry.yml
SUCCESS: 1 rules found
amtool 管理工具可以检查:
[opt/alertmanager/config]$ ../amtool check-config config.yml
Checking 'config.yml' SUCCESS
Found:
- global config
- route
- 0 inhibit rules
- 2 receivers
- 1 templates
SUCCESS
查看:
# ./amtool alert --alertmanager.url=http://localhost:9093
Alertname Starts At Summary
内存使用率过高 2019-04-09 13:14:45 CST Instance 192.168.1.12:9100 内存使用率过高
配置AlertManager
使用email报警的AlertManager的配置文件示意:
# 全局配置项
global:
resolve_timeout: 5m #处理超时时间,默认是5分钟
smtp_smarthost: 'X.X.X.X' #SMTP主机,如果不采用邮件报警可以不设置
smtp_from: '[email protected]' #发信人的邮箱
smtp_auth_username: '[email protected]' #发信人账号,一般就是邮箱,企业smtp服务器很多只验证IP,视具体情况而定
smtp_auth_password: '******' #密码
smtp_require_tls: false #smtp服务器是否要求tls加密,视具体情况而定。
route: #所有告警信息进入的根路由,报警分发策略
group_by: ['alertname'] #分组标签
group_wait: 5s # 告警等待时间。告警产生后等待5s,如果有同组的一起发出
group_interval: 10s #两组告警的间隔时间
repeat_interval: 5m #重复告警的间隔时间,减少相同邮件的发送频率
receiver: 'mail' #默认接收者,如果告警没有被route 匹配,则发给它
# 上面的所有属性都由子路由继承
routes: #指定哪些组可以接受哪类消息
- receiver: 'default-receiver'
group_wait: 10s
match:
team: node
- receiver: 'jenkins'
group_wait: 10s
match:
servicetype: systemd
receivers:
- name: 'default-receiver'
email_configs:
- to: '[email protected]'
- name: 'jenkins'
webhook_configs:
- url: "https://my-jenkins.com/generic-webhook-trigger/invoke?token=example"
# send_resolved: false
里面的配置项说明:
resolve_timeout:告警状态从firing变成resolve之后保存多久才宣布告警接触。主要是为了解决某些监控指标在阈值边缘波动,一会儿好一会儿不好的情况。
-
route: route是报警的分发策略,优先从左向右的顺序进行匹配。
-
group:为了避免连续发送类似的告警通知,可以将相关告警分到同一组中进行报警。分组机制会将详细的告警信息合并成一个通知,在某些情况下,比如由于系统宕机或者网络不可达导致大量的告警被同时触发,分组机制就可以把这些被触发的报警合并为一个告警通知,避免一次性接收大量的告警通知:
group_by: ['altername']
当一个新的报警分组被创建后,需要等待至少
group_wait
的时间来初始化告警。这样实际上就缓冲了从Prometheus发送到AlertManager的告警,将告警按相同的标签分组而不是全部发送。但是这可能导致接收告警通知不及时,另外问题就是下次对告警规则进行评估的时候会收到相同的分组告警通知,这时候就使用group_interval
参数来进行配置,当上一个告警通知发送到group后,AlertManager会在等待group_interval
时长后,再将触发的报警发送给receiver。repeat_interval参数主要是用于配置告警信息发送成功后,再次被触发发送的时间间隔,可以根据业务的紧急情况定义。
-
receivers:定义报警的接收方式的配置,比如webhook的url,微信的api啊等,邮件的接收人。
AlertManager trigger Jenkins job
这里以webhook trigger Jenkins job,启动 node_exporter 服务来举例。
主要配置:
- Prometheus rule
- Alertmanager config
- Jenkins Generic Webhook Trigger plugin
- Jenkins job
Prometheus rule
config file /opt/prometheus/rules/node.yml
- name: exporter-status-webhook
rules:
- alert: NodeExporterDown-webhook
expr: up == 0
for: 10m
labels:
servicetype: nodeAlert
新创建了一条rule,主要是把名字和 label 改了。这个 label 用于告警的路由。也可以延用原来的 rule ,但是会导致不会发出报警邮件。
检查配置,重启服务
$ sudo systemctl restart prometheus
停止某个 node_exporter 服务,网页查看 alert 状态。
AlertManager config
接受告警,路由到 webhook
file: /opt/alertmanager/config/config.yml
route:
routes:
#### 新增 ############
- match:
servicetype: nodeAlert # 跟 Prometheus rule 配置的 label 对应
receiver: jenkins_nodeJob # 接收方,与 webhook 对应
repeat_interval: 5m
receivers:
....
- name: 'jenkins_nodeJob' # 与上面的 receiver 对应
webhook_configs:
## webhook url 为jenkins job webhook 地址, token 与 job 中的配置对应。
- url: "http://jenkins-url:8080/generic-webhook-trigger/invoke?token=jenkinsnodealearts"
send_resolved: false
Restart alertmanager
$ sudo systemctl restart alertmanager
Jenkins Generic Webhook Trigger plugin
Install Jenkins plugin: Generic Webhook Trigger
这个plugin 的作用就是接收 HTTP request, 从中提取值。
如下图,红色方框中定义了变量 instances ,以及这个变量用什么表达式获取的。
具体该怎么设置,可以参考红色椭圆框中的例子。调试的时候,用另一个椭圆框中的链接。
设置token,与alertmanager 对应,回顾之前的设置。
启用下面的配置,用于debug。
在Jenkins日志中就能看到 json 输出。
把这一段json 不太友好,可以先把它格式化,比如放到网页中 https://jsonpath.curiousconcept.com/
根据需求,定制消息。一步步检测,表达式应该是什么。(表达式从 $ 开始,逐步调试,然后才知道这个表达式怎么来的:.alerts[*].labels.instance)
获取值后,就可以根据需要来处理了。
Jenkins job
执行 Shell 来处理。
#!/bin/bash
set -xe
hostlist=`echo $instances | sed 's/:9100//g' | sed 's/"//g'| sed 's/\[//' | sed 's/\]//'| sed 's/,/\n/g'`
echo $hostlist
export StrictHostKeyChecking=no
for HOST in $hostlist
do
echo $HOST
ssh $HOST "sudo systemctl start node_exporter"
done