文章目录
1. prometheus报警设置:
. 介绍
Prometheus的架构中被划分为两个部分
,
- 在
Prometheus Server中定义告警规则
以及产生告警, Alertmanager组件
则用于处理这些由Prometheus产生的告警。Alertmanager即Prometheus体系中告警的统一处理中心。Alertmanager提供了多种内置第三方告警通知方式,同时还提供了对Webhook通知的支持,通过Webhook用户可以完成对告警更多个性化的扩展。
Alertmanager: 从 Prometheus server 端
接收到 alerts 后,会进行去重,分组,并路由到相应的接收方,发出报警,常见的接收方式有:电子邮件,微信,钉钉, slack等。
prometheus触发一条告警的过程:
prometheus—>触发阈值—>超出持续时间—>alertmanager—>分组|抑制|静默—>媒体类型—>邮件|钉钉|微信等。
在Prometheus中一条告警规则主要由以下几部分组成:
- 告警名称:用户需要为告警规则命名,当然对于命名而言,需要能够直接表达出该告警的主要内容
- 告警规则:告警规则实际上主要由PromQL进行定义,其实际意义是当表达式(PromQL)查询结果持续多长时间(During)后出发告警
Alertmanager的特性
Alertmanager除了提供基本的告警通知能力以外,还主要提供了如:分组、抑制以及静默等告警特性
分组(group): 将类似性质的警报合并为单个通知。
静默(silences): 是一种简单的特定时间静音的机制,
例如:服务器要升级维护可以先设置这个时间段告警静默。
抑制(inhibition): 当警报发出后,停止重复发送由此警报引发的其他警报即合并一个故障引起的多个报警事件,可以 消除冗余告警
2.自定义告警规则
Prometheus中的告警规则允许你基于PromQL表达式定义告警触发条件
,Prometheus后端对这些触发规则进行周期性计算,当满足触发条件后则会触发告警通知。默认情况下,用户可以通过Prometheus的Web界面查看这些告警规则以及告警的触发状态。当Promthues与Alertmanager关联之后,可以将告警发送到外部服务如Alertmanager中并通过Alertmanager可以对这些告警进行进一步的处理。
定义告警规则
groups:
- name: example
rules:
- alert: HighErrorRate
expr: job:request_latency_seconds:mean5m{job="myjob"} > 0.5
for: 10m
labels:
severity: page
annotations:
summary: High request latency
description: description info
可以将一组相关的规则设置定义在一个group下。
在每一个group中定义多个告警规则(rule)。
告警规则主要由以下几部分组成:
alert
:告警规则的名称。
expr
:基于PromQL表达式告警触发条件,用于计算是否有时间序列满足该条件。
for
:评估等待时间,可选参数。用于表示只有当触发条件持续一段时间后才发送告警。在等待期间新产生告警的状态为pending。
labels
:自定义标签,允许用户指定要附加到告警上的一组附加标签。
annotations
:用于指定一组附加信息,比如用于描述告警详细信息的文字等,annotations的内容在告警产生时会一同作为参数发送到Alertmanager。
让Prometheus启用定义的告警规则
在Prometheus全局配置文件中通过rule_files
指定一组告警规则文件的访问路径,Prometheus启动后会自动扫描这些路径下规则文件中定义的内容,并且根据这些规则计算是否向外部发送通知:
rule_files:
[ - <filepath_glob> ... ]
默认情况下Prometheus会每分钟对这些告警规则进行计算,
如果用户想自定义的告警计算周期
,则可以通过evaluation_interval
来覆盖默认的计算周期:
global:
[ evaluation_interval: <duration> | default = 1m ]
模板化
在告警规则文件的annotations中使用summary
描述告警的概要信息,description
用于描述告警的详细信息。
同时Alertmanager的UI也会根据这两个标签值,显示告警信息。为了让告警信息具有更好的可读性,Prometheus支持模板化label和annotations的中标签的值。
通过$labels
.变量可以访问当前告警实例中指定标签的值。$value
则可以获取当前PromQL表达式计算的样本值。
# To insert a firing element's label values:
{{ $labels.<labelname> }}
# To insert the numeric expression value of the firing element:
{{ $value }}
以通过模板化优化summary以及description的内容的可读性
- alert: KubeAPILatencyHigh
annotations:
message: The API server has a 99th percentile latency of {{ $value }} seconds
for {{ $labels.verb }} {{ $labels.resource }}.
expr: |
cluster_quantile:apiserver_request_latencies:histogram_quantile{job="apiserver",quantile="0.99",subresource!="log"} > 4
for: 10m
labels:
severity: critical
这条警报的大致含义是,假如 kube-apiserver 的 P99 响应时间大于 4 秒,并持续 10 分钟以上,就产生报警。
首先要注意的是由 for
指定的 Pending Duration。这个参数主要用于降噪,很多类似响应时间这样的指标都是有抖动的,通过指定 Pending Duration,我们可以 过滤掉这些瞬时抖动,让 on-call 人员能够把注意力放在真正有持续影响的问题上。
那么显然,下面这样的状况是不会触发这条警报规则的,因为虽然指标已经达到了警报阈值,但持续时间并不够长:
查看告警状态
如下所示,用户可以通过Prometheus WEB界面中的Alerts菜单查看当前Prometheus下的所有告警规则,以及其当前所处的活动状态。
同时对于已经pending或者firing的告警,Prometheus也会将它们存储到时间序列ALERTS{}
中。
可以通过表达式,查询告警实例:
ALERTS{alertname="<alert name>", alertstate="pending|firing", <additional alert labels>}
样本值为1表示当前告警处于活动状态(pending或者firing),当告警从活动状态转换为非活动状态时,样本值则为0。
示例:定义主机监控报警
修改Prometheus配置文件prometheus.yml,添加以下配置:
rule_files:
- /usr/local/prometheus/*.rules
在目录/usr/local/prometheus/下创建告警文件alert.rules内容如下:
groups:
- name: hostStatsAlert
rules:
- alert: hostCpuUsageAlert
expr: sum(avg without (cpu)(irate(node_cpu_seconds_total{mode!='idle'}[1m]))) by (instance) > 0.5
for: 1m
labels:
severity: page
annotations:
summary: "Instance {{ $labels.instance }} CPU usgae high"
description: "{{ $labels.instance }} CPU usage above 50% (current value: {{ $value }})"
- alert: hostMemUsageAlert
expr: (node_memory_MemTotal - node_memory_MemAvailable)/node_memory_MemTotal > 0.7
for: 1m
labels:
severity: page
annotations:
summary: "Instance {{ $labels.instance }} MEM usgae high"
description: "{{ $labels.instance }} MEM usage above 50% (current value: {{ $value }})"
重启Prometheus后访问Prometheus UI
http://127.0.0.1:9090/rules
可以查看当前以加载的规则文件。这里我将阀值调小了,但是配置文件忘记修改不必在意
切换到Alerts标签http://127.0.0.1:9090/alerts
可以查看当前告警的活动状态。
此时,我们可以手动拉高系统的CPU使用率
,验证Prometheus的告警流程,在主机上运行以下命令:
cat /dev/zero>/dev/null
查看CPU使用率情况,
Prometheus首次检测到满足触发条件后,hostCpuUsageAlert
显示由一条告警处于活动状态。由于告警规则中设置了1m的等待时间,当前告警状态为PENDING
,如果1分钟后告警条件持续满足,则会实际触发告警并且告警状态为FIRING,如下图所示:
2.下载并报警组件alertmanager
Alertmanager: 从 Prometheus server 端
接收到 alerts 后,会进行去重,分组,并路由到相应的接收方,发出报警,常见的接收方式有:电子邮件,微信,钉钉, slack等。
安装在prometheus中
tar xf alertmanager-0.21.0.linux-amd64.tar.gz -C /usr/local/ && cd /usr/local/
ln -s /usr/local/alertmanager-0.21.0.linux-amd64/ /usr/local/alertmanager
mkdir -p /usr/local/alertmanager/data/
vim /etc/systemd/system/alertmanager.service
[Unit]
Description=alertmanager
After=network.target
[Service]
Type=simple
User=prometheus
ExecStart=/usr/local/alertmanager/alertmanager --config.file=/usr/local/alertmanager/alert-test.yaml --storage.path=/usr/local/alertmanager/data/
Restart=on-failure
[Install]
WantedBy=multi-user.target
2.1 配置alertmanager
官方配置文档
https://prometheus.io/docs/alerting/configuration/
Alertmanager的配置主要包含两个部分:路由
(route)以及接收器
(receivers)。所有的告警信息都会从配置中的顶级路由(route)进入路由树,根据路由规则将告警信息发送给相应的接收器。
在Alertmanager中通过路由(Route)来定义告警的处理方式。路由是一个基于标签匹配的树状匹配结构。根据接收到告警的标签匹配相应的处理方式。
Alertmanager主要负责对Prometheus产生的告警进行统一处理
Alertmanager配置包含以下几个主要部分
:
全局配置(global):用于定义一些全局的公共参数,如全局的SMTP配置,Slack配置等内容;
模板(templates):用于定义告警通知时的模板,如HTML模板,邮件模板等;
告警路由(route):根据标签匹配,确定当前告警应该如何处理;
接收人(receivers):接收人是一个抽象的概念,它可以是一个邮箱
也可以是微信,Slack或者Webhook等,接收人一般配合告警路由使用;
抑制规则(inhibit_rules):合理设置抑制规则可以减少垃圾告警的产生
Alermanager会将数据保存到本地中,默认的存储路径为data/。因此,在启动Alertmanager之前需要创建相应的目录
2.2 邮件报警
cd /usr/local/alertmanager
#这个名字对应service文件
cp alertmanager.yml alert-test.yml
cat alert-test.yml
global:
resolve_timeout: 5m #未接收到告警后标记告警状态为resolved(已解决)
# 邮件报警
smtp_smarthost: 'smtp.qq.com:465'
smtp_from: '11573241340@qq.com'
smtp_auth_username: '11573241340@qq.com'
#这个为qq的授权码
smtp_auth_password: 'udwtewqtcdhcj'
smtp_hello: '@qq.com'
smtp_require_tls: false
route: #route用来设置报警的分发策略,发送给哪一个receiver
group_by: ['alertname'] #采用哪个标签来作为分组依据
group_wait: 10s #组告警等待时间。也就是告警产生后等待10s,如果有同组告警一起发出
group_interval: 10s #两组告警的间隔时间
repeat_interval: 2m #重复告警的间隔时间,减少相同邮件的发送频率
receiver: 'web.hook' #设置接收人
receivers:
- name: 'web.hook'
#webhook_configs:
#- url: 'http://127.0.0.1:5001/'
email_configs:
- to: '11573241340@qq.com'
-
#inhibit_rules: #禁止的规则
# - source_match: #源匹配级别
# severity: 'critical'
# target_match:
# severity: 'warning'
# equal: ['alertname', 'dev', 'instance']
检查alertmanager配置文件
./amtool check-config alertmanager.yml
告警分组:group_by
当使用Prometheus监控多个集群以及部署在集群中的应用和数据库服务
route:
receiver: 'default-receiver'
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
group_by: [cluster, alertname]
#对于不同级别的告警
routes:
- receiver: 'database-pager'
group_wait: 10s
match_re:
service: mysql|cassandra
- receiver: 'frontend-pager'
group_by: [product, environment]
match:
team: frontend
启动alertmanager服务
chown -R prometheus:prometheus /usr/local/alertmanager-0.21.0.linux-amd64/
systemctl status alertmanager.service
默认监听端口:9093
集群监听端口9094
lsof -i:9093
访问:http://IP:9093
2.3 定义告警规则
告警配置链接
# Alertmanager configuration
alerting:
alertmanagers:
- static_configs:
- targets:
- alertmanager:9093
开启告警配置
rule_files:
# 告警规则配置文件位置
- "rules/*.yml"
监控Alertmanager
- job_name: 'alertmanager'
static_configs:
- targets: ['172.20.32.218:9093']
检查并重新加载配置文件
./promtool check config prometheus.yml
2.4创建告警目录&添加报警规则(配置文件)
在prometheus.yml的同级目录下,创建rules目录,在该rules目录下创建node_alerts.yml文件,内容如下:
mkdir rules && cd rules/
vim node_alerts.yml
# groups:组告警
groups:
# name:组名。报警规则组名称
- name: general.rules
# rules:定义角色
rules:
# alert:告警名称。 任何实例5分钟内无法访问发出告警
- alert: NodeFilesystemUsage
# expr:表达式。 获取磁盘使用率 大于百分之80 触发
expr: 100 - (node_filesystem_free_bytes{mountpoint="/",fstype=~"ext4|xfs"} / node_filesystem_size_bytes{fstype=~"ext4|xfs"} * 100) > 80
# for:持续时间。 表示持续一分钟获取不到信息,则触发报警。0表示不使用持续时间
for: 1m
# labels:定义当前告警规则级别
labels:
# severity: 指定告警级别。
severity: warning
# annotations: 注释 告警通知
annotations:
# 调用标签具体指附加通知信息
summary: "Instance {{ $labels.instance }} :{{ $labels.mountpoint }} 分区使用率过高" # 自定义摘要
description: "{{ $labels.instance }} : {{ $labels.job }} :{{ $labels.mountpoint }} 这个分区使用大于百分之80% (当前值:{{ $value }})" # 自定义具体描述
重启alertmanager服务
再次访问
查看告警规则
查看告警
2.5 警报三种状态:
Inactive 警报未激活;
Pending:警报已满足测试表达式条件,但未达到for指定的持续时间;
Firing:警报满足测试表达式条件,且持续时间达到了for指定的持续时间;
最后查看邮件
QQ邮箱
2.3钉钉报警
自定义机器人唯一的 webhook,可以通过电脑端的钉钉申请,申请完成后记录下该机器人的 webhook。如图:
自定义功能
完成安全设置后,复制出机器人的 Webhook 地址
,可用于向这个群发送消息,格式如下
https://oapi.dingtalk.com/robot/send?access_token=XXXXXX
保管好 Webhook 地址,避免后有安全风险。
安全设置
安全设置目前有 3 种方式:
1. 自定义关键词
最多可以设置 10 个关键字,消息中至少包含其中 1 个关键字才可以发送成功。
例如:添加了一个自定义关键字:监控报警
则这个机器人所发送的消息,必须包含监控报警 这个词,才能发送成功。
2. 加签
首先
把 timestamp +“ \ n” +
密钥当做签名密钥,使用 HmacSHA256 算法计算签名,然后进行 Base64 编码,最后再把签名参数再进行 urlEncode,得到最终的签名(需要使用 UTF-8 字符集)。
签名代码示例(Java
)
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import java.net.URLEncoder;
public class Test {
public static void main(String[] args) throws Exception {
Long timestamp = System.currentTimeMillis();
String secret = "this is secret替换为密钥";
String stringToSign = timestamp + "\n" + secret;
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256"));
byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8"));
String sign = URLEncoder.encode(new String(Base64.encodeBase64(signData)),"UTF-8");
System.out.println(sign);
}
}
签名代码示例(Python
)
#python 3.8
import time
import hmac
import hashlib
import base64
import urllib.parse
timestamp = str(round(time.time() * 1000))
secret = 'this is secret'
secret_enc = secret.encode('utf-8')
string_to_sign = '{}\n{}'.format(timestamp, secret)
string_to_sign_enc = string_to_sign.encode('utf-8')
hmac_code = hmac.new(secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest()
sign = urllib.parse.quote_plus(base64.b64encode(hmac_code))
print(timestamp)
print(sign)
#python 2.7
import time
import hmac
import hashlib
import base64
import urllib
timestamp = long(round(time.time() * 1000))
secret = 'this is secret'
secret_enc = bytes(secret).encode('utf-8')
string_to_sign = '{}\n{}'.format(timestamp, secret)
string_to_sign_enc = bytes(string_to_sign).encode('utf-8')
hmac_code = hmac.new(secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest()
sign = urllib.quote_plus(base64.b64encode(hmac_code))
print(timestamp)
print(sign)
第二步
把 timestamp 和第一步得到的签名值分割到 URL 中。
https://oapi.dingtalk.com/robot/send?access_token=XXXXXX×&tamp=XXX&sign=XXX
3. IP 地址(段)
设定后,只有来自 IP 地址范围内的请求才会被正常处理。支持两种设置方式:IP,IP 段,暂不支持 IPv6 的地址白名单,格式如下:
安全设置的上述三种方式,需要至少设置其中一种
,以进行安全保护。校正不通过的消息将会发送失败,错误如下:
//消息内容中不包含任何关键词
{
“ERRCODE”:310000,
“ERRMSG”: “关键字不是在内容”
}
//时间戳无效
{
“ERRCODE”:310000,
“ ERRMSG “:”无效时间戳“
}
//签名不匹配
{
”ERRCODE“:310000,
”ERRMSG“: ”符号不匹配“
}
// IP地址不在白名单
{
” ERRCODE“:310000,
“ errmsg”:“ ip XXXX不在白名单中”
}
python加签命令行测试
#钉钉收到消息即发送成功!
curl 'https://oapi.dingtalk.com/robot/send?access_token=XXXXXX×tamp=XXXXXX&sign=XXXXXX' -H 'Content-Type: application/json' -d '{"msgtype": "text","text": {"content": " 我就是我, 不一样的烟火"}}'
使用docker运行
docker run -p 5000:5000 --name -e ROBOT_TOKEN=<钉钉机器人TOKEN> -e ROBOT_SECRET=<钉钉机器人安全SECRET> -e LOG_LEVEL=debug -e PROME_URL=prometheus.local dingtalk-hook -d cnych/alertmanager-dingtalk-hook:v0.3.5
环境变量配置
ROBOT_TOKEN
:钉钉机器人
TOKEN PROME_URL
:手动指定跳转后的 Promethues 地址,默认会是 Pod 的地址
LOG_LEVEL
:日志级别,设置成 debug 可以看到 AlertManager WebHook发送的数据,方便调试使用,不需调试可以不设置该环境变量
ROBOT_SECRET
:为钉钉机器人的安全设置密钥,机器人安全设置页面,加签一栏下面显示的 SEC 开头的字符串
在Kubernetes集群中运行
第一步建议将钉钉机器人TOKEN创建成Secret资源对象:
kubectl create secret generic dingtalk-secret --from-literal=token=<钉钉群聊的机器人TOKEN> --from-literal=secret=<钉钉群聊机器人的SECRET> -n kube-ops
定义Deployment和Service资源对象:(dingtalk-hook.yaml)
apiVersion: apps/v1
kind: Deployment
metadata:
name: dingtalk-hook
namespace: kube-ops
spec:
selector:
matchLabels:
app: dingtalk-hook
template:
metadata:
labels:
app: dingtalk-hook
spec:
containers:
- name: dingtalk-hook
image: cnych/alertmanager-dingtalk-hook:v0.3.6
imagePullPolicy: IfNotPresent
ports:
- containerPort: 5000
name: http
env:
- name: PROME_URL
value: prometheus.local
- name: LOG_LEVEL
value: debug
- name: ROBOT_TOKEN
valueFrom:
secretKeyRef:
name: dingtalk-secret
key: token
- name: ROBOT_SECRET
valueFrom:
secretKeyRef:
name: dingtalk-secret
key: secret
resources:
requests:
cpu: 50m
memory: 100Mi
limits:
cpu: 50m
memory: 100Mi
---
apiVersion: v1
kind: Service
metadata:
name: dingtalk-hook
namespace: kube-ops
spec:
selector:
app: dingtalk-hook
ports:
- name: hook
port: 5000
targetPort: http
直接创建上面的资源对象
kubectl apply -f dingtalk-hook.yaml
kubectl get pods -n kube-ops
NAME READY STATUS RESTARTS AGE
dingtalk-hook-c4fcd8cd6-q22b6 1/1 Running 0 45m
最后在AlertManager中 webhook 地址直接通过 DNS 形式访问
receivers:
- name: 'webhook'
webhook_configs:
- url: 'http://dingtalk-hook.kube-ops.svc.cluster.local:5000'
send_resolved: true