prometheus 的几种告警方式
prometheus 我们都知道它是最近几年特别火的一个开源的监控工具,原生支持 kubernetes,如果你使用的是 kubernetes 集群,那么使用 prometheus 将会是非常方便的,而且 prometheus 也提供了报警工具alertmanager
,实际上在 prometheus 的架构中,告警能力是单独的一部分,主要是通过自定义一堆的rule
即告警规则,来周期性的对告警规则进行计算,并且会根据设置的报警触发条件,如果满足,就会进行告警,也就是会向alertmanager
发送告警信息,进而由alertmanager
进行告警。
那么,alertmanager
告警又是通过何种途径呢?其实有很多种方式,例如:
- 邮件告警
- 企业微信告警
- 钉钉告警
- slack 告警
- webhook 接口方式告警
其实还有一些,但这些都不重要,这些只是工具,重要的是如何运用,下面就介绍下使用 webhook 的方式来让 alertmanager 调用接口,发送POST
请求完成告警消息的推送,而这个推送可以是邮件,也可以是微信,钉钉等。
调用接口以邮件形式告警
大体流程是这样的,首先在我们定义好一堆告警规则之后,如果触发条件,alertmanager 会将报警信息推送给接口,然后我们的这个接口会做一些类似与聚合、汇总、优化的一些操作,然后将处理过的报警信息再以邮件的形式发送给指定的人或者组。也就是下面这个图:
我们这里的重点主要是如何写这个 webhook,以及写 webhook 的时候需要注意什么?下面将一一讲解
假设你有一个 prometheus 监控系统,并且告警规则都已配置完成
配置 alertmanager
首先得先配置 alertmanager,让其可以调用接口,配置方式很简单,只需要指定一下接口地址即可,如下:
receivers:
- webhook_configs:
url: http://10.127.34.107:5000/webhook
send_resolved: true
这就完了!当然可以指定多种告警方式
这样配置完成后,alertmanger 就会把告警信息以 POST 请求方式调用接口
编写一个最简单的接口
既然是用 python 来编写一个接口,那么肯定是用 flask 的,代码也非常简单,如下:
import json
from flask import Flask, request
from gevent.pywsgi import WSGIServer
app = Flask(__name__)
@app.route('/webhook', methods=['POST'])
def webhook():
prometheus_data = json.loads(request.data)
print(prometheus_data)
return "test"
if __name__ == '__main__':
WSGIServer(('0.0.0.0', 5000), app).serve_forever()
上面导入的一些模块,记得要去下载哦
pip install flask
pip install gevent
这样的话,我们直接运行此段代码,此时机器上会监听 5000 端口,如果此时 prometheus 有告警,那么我们就会看到 prometheus 传过来的数据格式是什么样的了,这里我贴一个示例:
{
'receiver': 'webhook',
'status': 'firing',
'alerts': [{
'status': 'firing',
'labels': {
'alertname': '内存使用率',
'instance': '10.127.92.100',
'job': 'sentry',
'severity': 'warning',
'team': 'ops'
},
'annotations': {
'description': '内存使用率已超过55%,内存使用率:58%',
'summary': '内存使用率'
},
'startsAt': '2020-12-30T07:20:08.775177336Z',
'endsAt': '0001-01-01T00:00:00Z',
'generatorURL': 'http://prometheus-server:9090/graph?g0.expr=round%28%281+-+%28node_memory_MemAvailable_bytes%7Bjob%3D%22sentry%22%7D+%2F+%28node_memory_MemTotal_bytes%7Bjob%3D%22sentry%22%7D%29%29%29+%2A+100%29+%3E+55&g0.tab=1',
'fingerprint': '09f94bd1aa7da54f'
}, {
'status': 'firing',
'labels': {
'alertname': '内存使用率',
'instance': '10.127.92.101',
'job': 'sentry',
'severity': 'warning',
'team': 'ops'
},
'annotations': {
'description': '内存使用率已超过55%,内存使用率:58%',
'summary': '内存使用率'
},
'startsAt': '2020-12-30T07:20:08.775177336Z',
'endsAt': '0001-01-01T00:00:00Z',
'generatorURL': 'http://prometheus-server:9090/graph?g0.expr=round%28%281+-+%28node_memory_MemAvailable_bytes%7Bjob%3D%22sentry%22%7D+%2F+%28node_memory_MemTotal_bytes%7Bjob%3D%22sentry%22%7D%29%29%29+%2A+100%29+%3E+55&g0.tab=1',
'fingerprint': '8a972e4907cf2c60'
}],
'groupLabels': {
'alertname': '内存使用率'
},
'commonLabels': {
'alertname': '内存使用率',
'job': 'sentry',
'severity': 'warning',
'team': 'ops'
},
'commonAnnotations': {
'summary': '内存使用率'
},
'externalURL': 'http://alertmanager-server:9093',
'version': '4',
'groupKey': '{}:{alertname="内存使用率"}',
'truncatedAlerts': 0
}
通过 prometheus 传过来的告警信息,可以看到是一个标准的json
,我们在使用python
在做处理时,需要先将json
字符串转换成python
的字典,可以用json
这个模块来实现,通过这个json
我们可以得到以下信息(非常重要):
- 每次发出的
json
数据流中的报警信息是同一个类型的报警,比如这里都是关于内存的 status
:表示告警的状态,两种:firing
和resolved
alerts
:是一个列表,里面的元素是由字典组成,每一个元素都是一条具体的告警信息commonLabels
:这里面就是一些公共的信息
剩下的几个 key 都比较好理解,就不一一说了,下面结合 prometheus 的一些 rule 来看下这个告警是凭什么这样发的。
# cat system-rule.yaml #文件名随意设置,因为prometheus的配置里配置的是: *.yaml
groups:
- name: sentry
rules:
- alert: "Memory Usage"
expr: round((1-(node_memory_MemAvailable_bytes{
job='sentry'} / (node_memory_MemTotal_bytes{
job='sentry'})))* 100) > 85
for: 5m
labels:
team: ops
severity: warning
cloud: yizhuang
annotations:
summary: "Memory usage is too high and over 85% for 5min"
description: "The current host {
{$labels.instance}}' memory usage is {
{ $value }}%"
这里就是配置的告警规则,告诉 prometheus 应该按照什么方式进行告警,配置完成后,要在 prometheus 的配置里引用下,如下所示:
# cat prometheus.yml
global:
scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
# scrape_timeout is set to the global default (10s).
# Alertmanager configuration
alerting:
alertmanagers:
- static_configs:
- targets: ['10.10.10.111:9093']
# 就是这里,看这里
rule_files:
- "/alertmanager/rule/*.yaml" #文件目录随意设置
...
...
...
此处省略一堆配置
到这里应该就知道告警规则是什么发出来的了吧,然后也应该知道告警内容为什么是这样的了吧,嗯,下面看下最关键的地方
处理原始告警信息并进行邮件告警
原始的告警信息看起来还挺规则的,只需要拼接下就可以了,但是有一个问题就是alerts
里面的startsAt
和endsAt
这俩时间格式有些问题,是 UTC 时区的时间,需要转换下。还有一个地方需要注意的,最外层的status
如果是firing
状态,就不代表alerts
中的status
就一定都是firing
,还有可能是resolved
,如下json
所示:
{
'receiver'