Prometheus告警处理

  导航:这里主要是列出一个prometheus一些系统的学习过程,最后按照章节顺序查看,由于写作该文档经历了不同时期,所以在文中有时出现

的云环境不统一,但是学习具体使用方法即可,在最后的篇章,有一个完整的腾讯云的实战案例。

  1.什么是prometheus?

  2.Prometheus安装

  3.Prometheus的Exporter详解

  4.Prometheus的PromQL

  5.Prometheus告警处理

  6.Prometheus的集群与高可用

  7.Prometheus服务发现

  8.kube-state-metrics 和 metrics-server

  9.监控kubernetes集群的方式

  10.prometheus operator

  11.Prometheus实战之联邦+高可用+持久

  12.Prometheus实战之配置汇总

  13.Grafana简单用法

  14.Grafana SQL汇总

  15.prometheus SQL汇总

  参考:

  https://prometheus.io/docs/prometheus/latest/configuration/configuration/#kubernetes_sd_config

  https://yunlzheng.gitbook.io/prometheus-book/part-iii-prometheus-shi-zhan/readmd/use-prometheus-monitor-kubernetes

  https://www.bookstack.cn/read/prometheus_practice/introduction-README.md

  https://www.kancloud.cn/huyipow/prometheus/521184

  https://www.qikqiak.com/k8s-book/docs/

 

  本章我们将探索Prometheus的告警处理机制,告警能力在Prometheus的架构中被划分为两个部分,在Prometheus Server中定义告警规则以及产生告警,Alertmanager组件则用于处理这些由Prometheus产生的告警。Alertmanager即Prometheus体系中告警的统一处理中心。Alertmanager提供了多种内置第三方告警通知方式,同时还提供了对Webhook通知的支持,通过Webhook用户可以完成对告警更多个性化的扩展。 

  本章主要内容:

  • 在Prometheus中自定义告警规则
  • 理解Alertmanager特性
  • 基于标签的动态告警处理
  • 将告警通知发送到第三方服务
  • 如何使用Webhook扩展Alertmanager
  • 以及一些其他的性能优化模式

 

1.Prometheus告警简介

  告警能力在Prometheus的架构中被划分成两个独立的部分。如下所示,通过在Prometheus中定义AlertRule(告警规则),Prometheus会周期性的对告警规则进行计算,如果满足告警触发条件就会向Alertmanager发送告警信息。

                        Prometheus告警处理

  在Prometheus中一条告警规则主要由以下几部分组成:

  • 告警名称:用户需要为告警规则命名,当然对于命名而言,需要能够直接表达出该告警的主要内容
  • 告警规则:告警规则实际上主要由PromQL进行定义,其实际意义是当表达式(PromQL)查询结果持续多长时间(During)后出发告警

  在Prometheus中,还可以通过Group(告警组)对一组相关的告警进行统一定义。当然这些定义都是通过YAML文件来统一管理的。

  Alertmanager作为一个独立的组件,负责接收并处理来自Prometheus Server(也可以是其它的客户端程序)的告警信息。Alertmanager可以对这些告警信息进行进一步的处理,比如当接收到大量重复告警时能够消除重复的告警信息,同时对告警信息进行分组并且路由到正确的通知方,Prometheus内置了对邮件,Slack等多种通知方式的支持,同时还支持与Webhook的集成,以支持更多定制化的场景。例如,目前Alertmanager还不支持钉钉,那用户完全可以通过Webhook与钉钉机器人进行集成,从而通过钉钉接收告警信息。同时AlertManager还提供了静默和告警抑制机制来对告警通知行为进行优化。

 

2.Alertmanager特性

  Alertmanager除了提供基本的告警通知能力以外,还主要提供了如:分组、抑制以及静默等告警特性:

2.1 分组

  分组机制可以将详细的告警信息合并成一个通知。在某些情况下,比如由于系统宕机导致大量的告警被同时触发,在这种情况下分组机制可以将这些被触发的告警合并为一个告警通知,避免一次性接受大量的告警通知,而无法对问题进行快速定位。

  例如,当集群中有数百个正在运行的服务实例,并且为每一个实例设置了告警规则。假如此时发生了网络故障,可能导致大量的服务实例无法连接到数据库,结果就会有数百个告警被发送到Alertmanager。

  而作为用户,可能只希望能够在一个通知中中就能查看哪些服务实例收到影响。这时可以按照服务所在集群或者告警名称对告警进行分组,而将这些告警内聚在一起成为一个通知。

  告警分组,告警时间,以及告警的接受方式可以通过Alertmanager的配置文件进行配置。

2.2 抑制

  抑制是指当某一告警发出后,可以停止重复发送由此告警引发的其它告警的机制。

  例如,当集群不可访问时触发了一次告警,通过配置Alertmanager可以忽略与该集群有关的其它所有告警。这样可以避免接收到大量与实际问题无关的告警通知。

  抑制机制同样通过Alertmanager的配置文件进行设置。

2.3 静默

  静默提供了一个简单的机制可以快速根据标签对告警进行静默处理。如果接收到的告警符合静默的配置,Alertmanager则不会发送告警通知。

  静默设置需要在Alertmanager的Werb页面上进行设置。

 

3.自定义Prometheus告警规则

  Prometheus中的告警规则允许你基于PromQL表达式定义告警触发条件,Prometheus后端对这些触发规则进行周期性计算,当满足触发条件后则会触发告警通知。默认情况下,用户可以通过Prometheus的Web界面查看这些告警规则以及告警的触发状态。当Promthues与Alertmanager关联之后,可以将告警发送到外部服务如Alertmanager中并通过Alertmanager可以对这些告警进行进一步的处理。

 

3.1定义告警规则

  一条典型的告警规则如下所示:

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 ]

3.2 模板化

  一般来说,在告警规则文件的annotations中使用summary描述告警的概要信息,description用于描述告警的详细信息。同时Alertmanager的UI也会根据这两个标签值,显示告警信息。为了让告警信息具有更好的可读性,Prometheus支持模板化label和annotations的中标签的值。

  通过$labels.<labelname>变量可以访问当前告警实例中指定标签的值。$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的内容的可读性:

groups:
- name: example
  rules:

  # Alert for any instance that is unreachable for >5 minutes.
  - alert: InstanceDown
    expr: up == 0
    for: 5m
    labels:
      severity: page
    annotations:
      summary: "Instance {{ $labels.instance }} down"
      description: "{{ $labels.instance }} of job {{ $labels.job }} has been down for more than 5 minutes."

  # Alert for any instance that has a median request latency >1s.
  - alert: APIHighRequestLatency
    expr: api_http_request_latencies_second{quantile="0.5"} > 1
    for: 10m
    annotations:
      summary: "High request latency on {{ $labels.instance }}"
      description: "{{ $labels.instance }} has a median request latency above 1s (current value: {{ $value }}s)"

3.3查看告警状态

  如下所示,用户可以通过Prometheus WEB界面中的Alerts菜单查看当前Prometheus下的所有告警规则,以及其当前所处的活动状态。

                                告警活动状态

  同时对于已经pending或者firing的告警,Prometheus也会将它们存储到时间序列ALERTS{}中。

  可以通过表达式,查询告警实例:

ALERTS{alertname="<alert name>", alertstate="pending|firing", <additional alert labels>}

  样本值为1表示当前告警处于活动状态(pending或者firing),当告警从活动状态转换为非活动状态时,样本值则为0。

 

3.4 实例:定义主机监控告警

  修改Prometheus配置文件prometheus.yml,添加以下配置:

rule_files:
  - /etc/prometheus/rules/*.rules

  在目录/etc/prometheus/rules/下创建告警文件hoststats-alert.rules内容如下:

groups:
- name: hostStatsAlert
  rules:
  - alert: hostCpuUsageAlert
    expr: sum(avg without (cpu)(irate(node_cpu{mode!='idle'}[5m]))) by (instance) > 0.85
    for: 1m
    labels:
      severity: page
    annotations:
      summary: "Instance {{ $labels.instance }} CPU usgae high"
      description: "{{ $labels.instance }} CPU usage above 85% (current value: {{ $value }})"
  - alert: hostMemUsageAlert
    expr: (node_memory_MemTotal - node_memory_MemAvailable)/node_memory_MemTotal > 0.85
    for: 1m
    labels:
      severity: page
    annotations:
      summary: "Instance {{ $labels.instance }} MEM usgae high"
      description: "{{ $labels.instance }} MEM usage above 85% (current value: {{ $value }})"

  重启Prometheus后访问Prometheus UIhttp://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,如下图所示:

  在这一小节中介绍了如何配置和使用Prometheus提供的告警能力,并且尝试实现了对主机CPU以及内存的告警规则设置。目前为止,我们只能通过Prometheus UI查看当前告警的活动状态。接下来,接下来我们将尝试利用Prometheus体系中的另一个组件Alertmanager对这些触发的告警进行处理,实现告警通知。

 

4.部署AlertManager

  Alertmanager和Prometheus Server一样均采用Golang实现,并且没有第三方依赖。一般来说我们可以通过以下几种方式来部署Alertmanager:二进制包、容器以及源码方式安装。

 

4.1 使用二进制包部署AlertManager

  获取并安装软件包

  Alertmanager最新版本的下载地址可以从Prometheus官方网站https://prometheus.io/download/获取。

export VERSION=0.15.2
curl -LO https://github.com/prometheus/alertmanager/releases/download/v$VERSION/alertmanager-$VERSION.darwin-amd64.tar.gz
tar xvf alertmanager-$VERSION.darwin-amd64.tar.gz

  创建alertmanager配置文件

  Alertmanager解压后会包含一个默认的alertmanager.yml配置文件,内容如下所示:

global:
  resolve_timeout: 5m

route:
  group_by: ['alertname']
  group_wait: 10s
  group_interval: 10s
  repeat_interval: 1h
  receiver: 'web.hook'
receivers:
- name: 'web.hook'
  webhook_configs:
  - url: 'http://127.0.0.1:5001/'
inhibit_rules:
  - source_match:
      severity: 'critical'
    target_match:
      severity: 'warning'
    equal: ['alertname', 'dev', 'instance']

  Alertmanager的配置主要包含两个部分:路由(route)以及接收器(receivers)。所有的告警信息都会从配置中的顶级路由(route)进入路由树,根据路由规则将告警信息发送给相应的接收器。

  在Alertmanager中可以定义一组接收器,比如可以按照角色(比如系统运维,数据库管理员)来划分多个接收器。接收器可以关联邮件,Slack以及其它方式接收告警信息。

  当前配置文件中定义了一个默认的接收者default-receiver由于这里没有设置接收方式,目前只相当于一个占位符。关于接收器的详细介绍会在后续章节介绍。

  在配置文件中使用route定义了顶级的路由,路由是一个基于标签匹配规则的树状结构。所有的告警信息从顶级路由开始,根据标签匹配规则进入到不同的子路由,并且根据子路由设置的接收器发送告警。目前配置文件中只设置了一个顶级路由route并且定义的接收器为default-receiver。因此,所有的告警都会发送给default-receiver。关于路由的详细内容会在后续进行详细介绍。

  

  启动Alertmanager

  Alermanager会将数据保存到本地中,默认的存储路径为data/。因此,在启动Alertmanager之前需要创建相应的目录:

./alertmanager

  用户也在启动Alertmanager时使用参数修改相关配置。--config.file用于指定alertmanager配置文件路径,--storage.path用于指定数据存储路径。

 

  查看运行状态

  Alertmanager启动后可以通过9093端口访问,http://192.168.33.10:9093

                        Alertmanager页面

  Alert菜单下可以查看Alertmanager接收到的告警内容。Silences菜单下则可以通过UI创建静默规则,这部分我们会在后续部分介绍。进入Status菜单,可以看到当前系统的运行状态以及配置信息。

 

4.2 关联Prometheus与Alertmanager

  在Prometheus的架构中被划分成两个独立的部分。Prometheus负责产生告警,而Alertmanager负责告警产生后的后续处理。因此Alertmanager部署完成后,需要在Prometheus中设置Alertmanager相关的信息。

  编辑Prometheus配置文件prometheus.yml,并添加以下内容

alerting:
  alertmanagers:
    - static_configs:
        - targets: ['localhost:9093']

  重启Prometheus服务,成功后,可以从http://192.168.33.10:9090/config查看alerting配置是否生效。

  此时,再次尝试手动拉高系统CPU使用率:

cat /dev/zero>/dev/null

  等待Prometheus告警进行触发状态:

  查看Alertmanager UI此时可以看到Alertmanager接收到的告警信息。

  目前为止,已经成功安装部署了Alertmanager并且与Prometheus关联,能够正常接收来自Prometheus的告警信息。接下来将详细介绍Alertmanager是如何处理这些接收到的告警信息的。

 

5.Alertmanager配置概述

  在上面的部分中已经简单介绍过,在Alertmanager中通过路由(Route)来定义告警的处理方式。路由是一个基于标签匹配的树状匹配结构。根据接收到告警的标签匹配相应的处理方式。这里将详细介绍路由相关的内容。

  Alertmanager主要负责对Prometheus产生的告警进行统一处理,因此在Alertmanager配置中一般会包含以下几个主要部分:

  • 全局配置(global):用于定义一些全局的公共参数,如全局的SMTP配置,Slack配置等内容;
  • 模板(templates):用于定义告警通知时的模板,如HTML模板,邮件模板等;
  • 告警路由(route):根据标签匹配,确定当前告警应该如何处理;
  • 接收人(receivers):接收人是一个抽象的概念,它可以是一个邮箱也可以是微信,Slack或者Webhook等,接收人一般配合告警路由使用;
  • 抑制规则(inhibit_rules):合理设置抑制规则可以减少垃圾告警的产生

  其完整配置格式如下:

global:
  [ resolve_timeout: <duration> | default = 5m ]
  [ smtp_from: <tmpl_string> ] 
  [ smtp_smarthost: <string> ] 
  [ smtp_hello: <string> | default = "localhost" ]
  [ smtp_auth_username: <string> ]
  [ smtp_auth_password: <secret> ]
  [ smtp_auth_identity: <string> ]
  [ smtp_auth_secret: <secret> ]
  [ smtp_require_tls: <bool> | default = true ]
  [ slack_api_url: <secret> ]
  [ victorops_api_key: <secret> ]
  [ victorops_api_url: <string> | default = "https://alert.victorops.com/integrations/generic/20131114/alert/" ]
  [ pagerduty_url: <string> | default = "https://events.pagerduty.com/v2/enqueue" ]
  [ opsgenie_api_key: <secret> ]
  [ opsgenie_api_url: <string> | default = "https://api.opsgenie.com/" ]
  [ hipchat_api_url: <string> | default = "https://api.hipchat.com/" ]
  [ hipchat_auth_token: <secret> ]
  [ wechat_api_url: <string> | default = "https://qyapi.weixin.qq.com/cgi-bin/" ]
  [ wechat_api_secret: <secret> ]
  [ wechat_api_corp_id: <string> ]
  [ http_config: <http_config> ]

templates:
  [ - <filepath> ... ]

route: <route>

receivers:
  - <receiver> ...

inhibit_rules:
  [ - <inhibit_rule> ... ]

  在全局配置中需要注意的是resolve_timeout,该参数定义了当Alertmanager持续多长时间未接收到告警后标记告警状态为resolved(已解决)。该参数的定义可能会影响到告警恢复通知的接收时间,读者可根据自己的实际场景进行定义,其默认值为5分钟。在接下来的部分,将已一些实际的例子解释Alertmanager的其它配置内容。

 

6.基于标签的告警处理路由

  在Alertmanager的配置中会定义一个基于标签匹配规则的告警路由树,以确定在接收到告警后Alertmanager需要如何对其进行处理:

route: <route>

  其中route中则主要定义了告警的路由匹配规则,以及Alertmanager需要将匹配到的告警发送给哪一个receiver,一个最简单的route定义如下所示:

route:
  group_by: ['alertname']
  receiver: 'web.hook'
receivers:
- name: 'web.hook'
  webhook_configs:
  - url: 'http://127.0.0.1:5001/'

  如上所示:在Alertmanager配置文件中,我们只定义了一个路由,那就意味着所有由Prometheus产生的告警在发送到Alertmanager之后都会通过名为web.hook的receiver接收。这里的web.hook定义为一个webhook地址。当然实际场景下,告警处理可不是这么简单的一件事情,对于不同级别的告警,我们可能会有完全不同的处理方式,因此在route中,我们还可以定义更多的子Route,这些Route通过标签匹配告警的处理方式,route的完整定义如下:

[ receiver: <string> ]
[ group_by: '[' <labelname>, ... ']' ]
[ continue: <boolean> | default = false ]

match:
  [ <labelname>: <labelvalue>, ... ]

match_re:
  [ <labelname>: <regex>, ... ]

[ group_wait: <duration> | default = 30s ]
[ group_interval: <duration> | default = 5m ]
[ repeat_interval: <duration> | default = 4h ]

routes:
  [ - <route> ... ]

6.1 路由匹配

  每一个告警都会从配置文件中顶级的route进入路由树,需要注意的是顶级的route必须匹配所有告警(即不能有任何的匹配设置match和match_re),每一个路由都可以定义自己的接受人以及匹配规则。默认情况下,告警进入到顶级route后会遍历所有的子节点,直到找到最深的匹配route,并将告警发送到该route定义的receiver中。但如果route中设置continue的值为false,那么告警在匹配到第一个子节点之后就直接停止。如果continue为true,报警则会继续进行后续子节点的匹配。如果当前告警匹配不到任何的子节点,那该告警将会基于当前路由节点的接收器配置方式进行处理。

  其中告警的匹配有两种方式可以选择。一种方式基于字符串验证,通过设置match规则判断当前告警中是否存在标签labelname并且其值等于labelvalue。第二种方式则基于正则表达式,通过设置match_re验证当前告警标签的值是否满足正则表达式的内容。

  如果警报已经成功发送通知, 如果想设置发送告警通知之前要等待时间,则可以通过repeat_interval参数进行设置。

 

6.2 告警分组

  在之前的部分有讲过,Alertmanager可以对告警通知进行分组,将多条告警合合并为一个通知。这里我们可以使用group_by来定义分组规则。基于告警中包含的标签,如果满足group_by中定义标签名称,那么这些告警将会合并为一个通知发送给接收器。

  有的时候为了能够一次性收集和发送更多的相关信息时,可以通过group_wait参数设置等待时间,如果在等待时间内当前group接收到了新的告警,这些告警将会合并为一个通知向receiver发送。

  而group_interval配置,则用于定义相同的Group之间发送告警通知的时间间隔。

  例如,当使用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

  默认情况下所有的告警都会发送给集群管理员default-receiver,因此在Alertmanager的配置文件的根路由中,对告警信息按照集群以及告警的名称对告警进行分组。

  如果告警时来源于数据库服务如MySQL或者Cassandra,此时则需要将告警发送给相应的数据库管理员(database-pager)。这里定义了一个单独子路由,如果告警中包含service标签,并且service为MySQL或者Cassandra,则向database-pager发送告警通知,由于这里没有定义group_by等属性,这些属性的配置信息将从上级路由继承,database-pager将会接收到按cluster和alertname进行分组的告警通知。

  而某些告警规则来源可能来源于开发团队的定义,这些告警中通过添加标签team来标示这些告警的创建者。在Alertmanager配置文件的告警路由下,定义单独子路由用于处理这一类的告警通知,如果匹配到告警中包含标签team,并且team的值为frontend,Alertmanager将会按照标签product和environment对告警进行分组。此时如果应用出现异常,开发团队就能清楚的知道哪一个环境(environment)中的哪一个应用程序出现了问题,可以快速对应用进行问题定位。

 

7.使用Receiver接收告警信息

  前上一小节已经讲过,在Alertmanager中路由负责对告警信息进行分组匹配,并将像告警接收器发送通知。告警接收器可以通过以下形式进行配置:

receivers:
  - <receiver> ...

  每一个receiver具有一个全局唯一的名称,并且对应一个或者多个通知方式:

name: <string>
email_configs:
  [ - <email_config>, ... ]
hipchat_configs:
  [ - <hipchat_config>, ... ]
pagerduty_configs:
  [ - <pagerduty_config>, ... ]
pushover_configs:
  [ - <pushover_config>, ... ]
slack_configs:
  [ - <slack_config>, ... ]
opsgenie_configs:
  [ - <opsgenie_config>, ... ]
webhook_configs:
  [ - <webhook_config>, ... ]
victorops_configs:
  [ - <victorops_config>, ... ]

  目前官方内置的第三方通知集成包括:邮件、 即时通讯软件(如Slack、Hipchat)、移动应用消息推送(如Pushover)和自动化运维工具(例如:Pagerduty、Opsgenie、Victorops)。Alertmanager的通知方式中还可以支持Webhook,通过这种方式开发者可以实现更多个性化的扩展支持。

 

7.1 集成邮件系统

  邮箱应该是目前企业最常用的告警通知方式,Alertmanager内置了对SMTP协议的支持,因此对于企业用户而言,只需要一些基本的配置即可实现通过邮件的通知。

  在Alertmanager使用邮箱通知,用户只需要定义好SMTP相关的配置,并且在receiver中定义接收方的邮件地址即可。在Alertmanager中我们可以直接在配置文件的global中定义全局的SMTP配置:

global:
  [ smtp_from: <tmpl_string> ]
  [ smtp_smarthost: <string> ]
  [ smtp_hello: <string> | default = "localhost" ]
  [ smtp_auth_username: <string> ]
  [ smtp_auth_password: <secret> ]
  [ smtp_auth_identity: <string> ]
  [ smtp_auth_secret: <secret> ]
  [ smtp_require_tls: <bool> | default = true ]

  完成全局SMTP之后,我们只需要为receiver配置email_configs用于定义一组接收告警的邮箱地址即可,如下所示:

name: <string>
email_configs:
  [ - <email_config>, ... ]

  每个email_config中定义相应的接收人邮箱地址,邮件通知模板等信息即可,当然如果当前接收人需要单独的SMTP配置,那直接在email_config中覆盖即可:

[ send_resolved: <boolean> | default = false ]
to: <tmpl_string>
[ html: <tmpl_string> | default = '{{ template "email.default.html" . }}' ]
[ headers: { <string>: <tmpl_string>, ... } ]

  如果当前收件人需要接受告警恢复的通知的话,在email_config中定义send_resolved为true即可。

  如果所有的邮件配置使用了相同的SMTP配置,则可以直接定义全局的SMTP配置。

  这里,以Gmail邮箱为例,我们定义了一个全局的SMTP配置,并且通过route将所有告警信息发送到default-receiver中:

global:
  smtp_smarthost: smtp.gmail.com:587
  smtp_from: <smtp mail from>
  smtp_auth_username: <usernae>
  smtp_auth_identity: <username>
  smtp_auth_password: <password>

route:
  group_by: ['alertname']
  receiver: 'default-receiver'

receivers:
  - name: default-receiver
    email_configs:
      - to: <mail to address>
        send_resolved: true

  注意:新的Google账号安全规则需要使用”应用专有密码“作为邮箱登录密码

  这时如果手动拉高主机CPU使用率,使得监控样本数据满足告警触发条件。在SMTP配置正确的情况下,可以接收到如下的告警内容:

7.2 集成Slack

  Slack是非常流行的团队沟通应用,提供群组聊天和直接消息发送功能,支持移动端,Web 和桌面平台。在国外有大量的IT团队使用Slack作为团队协作平台。同时其提供了强大的集成能力,在Slack的基础上也衍生出了大量的ChatOps相关的技术实践。这部分将介绍如何将Slack集成到Alertmanager中。

 

7.2.1 认识Slack

  Slack作为一款即时通讯工具,协作沟通主要通过Channel(平台)来完成,用户可以在企业中根据用途添加多个Channel,并且通过Channel来集成各种第三方工具。

  例如,我们可以为监控建立一个单独的Channel用于接收各种监控信息:

                              创建Channel

  通过一个独立的Channle可以减少信息对用户工作的干扰,并且将相关信息聚合在一起:

                              Monitoring

  Slack的强大之处在于在Channel中添加各种第三方服务的集成,用户也可以基于Slack开发自己的聊天机器人来实现一些更高级的能力,例如自动化运维,提高开发效率等。

 

7.2.2 添加应用:Incomming Webhooks

  为了能够在Monitoring中接收来自Alertmanager的消息,我们需要在Channel的设置选项中使用"Add an App"为Monitoring channel添加一个名为Incoming WebHooks的应用:

 

                         添加Incomming Webhooks

  添加成功后Slack会显示Incoming WebHooks配置和使用方式:

                        Incomming Webhhook配置

  Incomming Webhook的工作方式很简单,Slack为当前Channel创建了一个用于接收消息的API地址:

https://hooks.slack.com/services/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

  用户只需要使用Post方式向Channel发送需要通知的消息即可,例如,我们可以在命令行中通过curl模拟一次消息通知:

curl -d "payload={'text': 'This is a line of text in a channel.\nAnd this is another line of text.'}" https://hooks.slack.com/services/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

  在网络正常的情况下,在Channel中会显示新的通知信息,如下所示:

                          测试消息

  除了发送纯文本以外,slack还支持在文本内容中添加链接,例如:

payload={"text": "A very important thing has occurred! <https://alert-system.com/alerts/1234|Click here> for details!"}

  此时接收到的消息中建辉包含一个可点击的超链接地址。除了payload以外,Incomming Webhhook还支持一些其他的参数:

参数 作用 示例
username 设置当前聊天机器人的名称 webhookbot
icon_url 当前聊天机器人的头像地址 https://slack.com/img/icons/app-57.png
icon_emoji 使用emoji作为聊天机器人的头像 :ghost:
channel 消息发送的目标channel, 需要直接发给特定用户时使用@username即可 #monitoring 或者 @username

  例如,使用以上参数发送一条更有趣的消息:

curl -X POST --data-urlencode "payload={'channel': '#monitoring', 'username': 'webhookbot', 'text': 'This is posted to #monitoring and comes from a bot named webhookbot.', 'icon_emoji': ':ghost:'}" https://hooks.slack.com/services/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

                自定义消息

 

7.2.3 在Alertmanager中使用Slack

  在了解了Slack以及Incomming Webhhook的基本使用方式后,在Alertmanager中添加Slack支持就非常简单了。

  在Alertmanager的全局配置中,将Incomming Webhhook地址作为slack_api_url添加到全局配置中即可:

global:
  slack_api_url: https://hooks.slack.com/services/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

  当然,也可以在每个receiver中单独定义自己的slack_configs即可:

receivers:
- name: slack
  slack_configs:
    - channel: '#monitoring'
      send_resolved: true

  这里如果我们手动拉高当前主机的CPU利用率,在#Monitoring平台中,我们会接收到一条告警信息如下所示:

 

                   告警信息

  而当告警项恢复正常后,则可以接收到如下通知:

                   告警恢复信息

  对于Incomming Webhhook支持的其它自定义参数,也可以在slack_config中进行定义,slack_config的主要配置如下:

channel: <tmpl_string>
[ send_resolved: <boolean> | default = false ]
[ api_url: <secret> | default = global.slack_api_url ]
[ icon_emoji: <tmpl_string> ]
[ icon_url: <tmpl_string> ]
[ link_names: <boolean> | default = false ]
[ username: <tmpl_string> | default = '{{ template "slack.default.username" . }}' ]
[ color: <tmpl_string> | default = '{{ if eq .Status "firing" }}danger{{ else }}good{{ end }}' ]
[ footer: <tmpl_string> | default = '{{ template "slack.default.footer" . }}' ]
[ pretext: <tmpl_string> | default = '{{ template "slack.default.pretext" . }}' ]
[ text: <tmpl_string> | default = '{{ template "slack.default.text" . }}' ]
[ title: <tmpl_string> | default = '{{ template "slack.default.title" . }}' ]
[ title_link: <tmpl_string> | default = '{{ template "slack.default.titlelink" . }}' ]
[ image_url: <tmpl_string> ]
[ thumb_url: <tmpl_string> ]

  如果要覆盖默认的告警内容,直接使用Go Template即可。例如:

color: '{{ if eq .Status "firing" }}danger{{ else }}good{{ end }}'

7.3 集成企业微信

  Alertmanager已经内置了对企业微信的支持,我们可以通过企业微信来管理报警,更进一步可以通过企业微信和微信的互通来直接将告警消息转发到个人微信上。

  prometheus官网中给出了企业微信的相关配置说明

# Whether or not to notify about resolved alerts.
[ send_resolved: <boolean> | default = false ]

# The API key to use when talking to the WeChat API.
[ api_secret: <secret> | default = global.wechat_api_secret ]

# The WeChat API URL.
[ api_url: <string> | default = global.wechat_api_url ]

# The corp id for authentication.
[ corp_id: <string> | default = global.wechat_api_corp_id ]

# API request data as defined by the WeChat API.
[ message: <tmpl_string> | default = '{{ template "wechat.default.message" . }}' ]
[ agent_id: <string> | default = '{{ template "wechat.default.agent_id" . }}' ]
[ to_user: <string> | default = '{{ template "wechat.default.to_user" . }}' ]
[ to_party: <string> | default = '{{ template "wechat.default.to_party" . }}' ]
[ to_tag: <string> | default = '{{ template "wechat.default.to_tag" . }}' ]

  企业微信相关概念说明请参考企业微信API说明,可以在企业微信的后台中建立多个应用,每个应用对应不同的报警分组,由企业微信来做接收成员的划分。具体配置参考如下:

global:
  resolve_timeout: 10m
  wechat_api_url: 'https://qyapi.weixin.qq.com/cgi-bin/'
  wechat_api_secret: '应用的secret,在应用的配置页面可以看到'
  wechat_api_corp_id: '企业id,在企业的配置页面可以看到'
templates:
- '/etc/alertmanager/config/*.tmpl'
route:
  group_by: ['alertname']
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 12h
  routes:
  - receiver: 'wechat'
    continue: true
inhibit_rules:
- source_match:
receivers:
- name: 'wechat'
  wechat_configs:
  - send_resolved: false
    corp_id: '企业id,在企业的配置页面可以看到'
    to_user: '@all'
    to_party: ' PartyID1 | PartyID2 '
    message: '{{ template "wechat.default.message" . }}'
    agent_id: '应用的AgentId,在应用的配置页面可以看到'
    api_secret: '应用的secret,在应用的配置页面可以看到'

  配置模板示例如下:

{{ define "wechat.default.message" }}
{{- if gt (len .Alerts.Firing) 0 -}}
{{- range $index, $alert := .Alerts -}}
{{- if eq $index 0 -}}
告警类型: {{ $alert.Labels.alertname }}
告警级别: {{ $alert.Labels.severity }}

=====================
{{- end }}
===告警详情===
告警详情: {{ $alert.Annotations.message }}
故障时间: {{ $alert.StartsAt.Format "2006-01-02 15:04:05" }}
===参考信息===
{{ if gt (len $alert.Labels.instance) 0 -}}故障实例ip: {{ $alert.Labels.instance }};{{- end -}}
{{- if gt (len $alert.Labels.namespace) 0 -}}故障实例所在namespace: {{ $alert.Labels.namespace }};{{- end -}}
{{- if gt (len $alert.Labels.node) 0 -}}故障物理机ip: {{ $alert.Labels.node }};{{- end -}}
{{- if gt (len $alert.Labels.pod_name) 0 -}}故障pod名称: {{ $alert.Labels.pod_name }}{{- end }}
=====================
{{- end }}
{{- end }}

{{- if gt (len .Alerts.Resolved) 0 -}}
{{- range $index, $alert := .Alerts -}}
{{- if eq $index 0 -}}
告警类型: {{ $alert.Labels.alertname }}
告警级别: {{ $alert.Labels.severity }}

=====================
{{- end }}
===告警详情===
告警详情: {{ $alert.Annotations.message }}
故障时间: {{ $alert.StartsAt.Format "2006-01-02 15:04:05" }}
恢复时间: {{ $alert.EndsAt.Format "2006-01-02 15:04:05" }}
===参考信息===
{{ if gt (len $alert.Labels.instance) 0 -}}故障实例ip: {{ $alert.Labels.instance }};{{- end -}}
{{- if gt (len $alert.Labels.namespace) 0 -}}故障实例所在namespace: {{ $alert.Labels.namespace }};{{- end -}}
{{- if gt (len $alert.Labels.node) 0 -}}故障物理机ip: {{ $alert.Labels.node }};{{- end -}}
{{- if gt (len $alert.Labels.pod_name) 0 -}}故障pod名称: {{ $alert.Labels.pod_name }};{{- end }}
=====================
{{- end }}
{{- end }}
{{- end }}

  这时如果某一容器频繁重启,可以接收到如下的告警内容:

                         告警

7.3.1 集成企业微信案例

1.企业ID获取

  首先访问企业微信官网:https://work.weixin.qq.com/

  注册完成之后,登录后台管理,在【我的企业】这里,先拿到后面用到的第一个配置:企业ID

 

2.部门ID获取

  在通讯录中,添加一个子部门,用于接收告警信息,后面把人加到该部门,这个人就能接收到告警信息了。

  可以看到部门id为2

 

3.告警AgentId和Secret获取

  告警AgentId和Secret获取是需要在企业微信后台,【应用管理】中,自建应用才能够获得的。这里网上介绍的非常多,都只是说了这一步骤,而忽略了其他几个重要的步骤。

  点击这个应用,可以看到我们想要的AgentId和Secret

  以上步骤完成后,我们就得到了配置Alertmanager的所有信息,包括:企业ID,AgentId,Secret和接收告警的部门id

 

4.配置Alertmanager服务

  主配置文件

global:
  resolve_timeout: 5m

  wechat_api_url: 'https://qyapi.weixin.qq.com/cgi-bin/'
  wechat_api_corp_id: 'wwd30f74a2a3aca657'      # 企业微信中企业ID
  wechat_api_secret: 'yIyc9g_2S0kxOTe2kwgZ0gWG6RVZ7AGB0m2qhUFgD34'      # 企业微信中,应用的Secret 

templates:
-  "/opt/alertmanager/templates/*.tmpl"

route:
  group_by: ['alertname']
  group_wait: 10s
  group_interval: 10s
  repeat_interval: 1m
  receiver: 'cn-web-prod'
receivers:
- name: 'cn-web-prod'
  wechat_configs:
  - send_resolved: true
    #message: '{{ template "wechat.default.message" . }}'
    to_party: '2'        # 企业微信中创建的接收告警的部门【告警机器人】的部门ID
    to_user: 'tc'       #这里有2点需要注意。1.用户不能在默认的最大部门下。2.无法配置多用户同时发送告警,所以多用户需要使用部门
    agent_id: '1000003'         # 企业微信中创建的应用的ID
    api_secret: 'yIyc9g_2S0kxOTe2kwgZ0gWG6RVZ7AGB0m2qhUFgD34'  #企业微信中,应用的Secret

5.微信告警模版(可选)

    对应配置文件中message字段引用。

# cat /opt/alertmanager/template/wechat.tmpl
{{ define "wechat.default.message" }}
{{- if gt (len .Alerts.Firing) 0 -}}
{{- range $index, $alert := .Alerts -}}
{{- if eq $index 0 }}
========= 监控报警 =========
告警状态:{{   .Status }}
告警级别:{{ .Labels.severity }}
告警类型:{{ $alert.Labels.alertname }}
故障主机: {{ $alert.Labels.instance }}
告警主题: {{ $alert.Annotations.summary }}
告警详情: {{ $alert.Annotations.message }}{{ $alert.Annotations.description}};
触发阀值:{{ .Annotations.value }}
故障时间: {{ ($alert.StartsAt.Add 28800e9).Format "2006-01-02 15:04:05" }}
========= = end =  =========
{{- end }}
{{- end }}
{{- end }}
{{- if gt (len .Alerts.Resolved) 0 -}}
{{- range $index, $alert := .Alerts -}}
{{- if eq $index 0 }}
========= 异常恢复 =========
告警类型:{{ .Labels.alertname }}
告警状态:{{   .Status }}
告警主题: {{ $alert.Annotations.summary }}
告警详情: {{ $alert.Annotations.message }}{{ $alert.Annotations.description}};
故障时间: {{ ($alert.StartsAt.Add 28800e9).Format "2006-01-02 15:04:05" }}
恢复时间: {{ ($alert.EndsAt.Add 28800e9).Format "2006-01-02 15:04:05" }}
{{- if gt (len $alert.Labels.instance) 0 }}
实例信息: {{ $alert.Labels.instance }}
{{- end }}
========= = end =  =========
{{- end }}
{{- end }}
{{- end }}
{{- end }}

    更多微信告警配置参考: https://prometheus.io/docs/alerting/latest/configuration/#wechat_config

 

7.4 集成钉钉:基于Webhook的扩展

7.4.1 自定义webhook群机器人

  通过钉钉客户端(如:桌面或者手机)进入到群设置后选择“群机器人”。将显示如下界面:

                    群机器人

  选择“自定义机器人”,并且按照提示填写机器人名称,获取机器人webhook地址,如下所示:

 

                  获取webhook地址

  webhook机器人创建成功后,用户就可以使用任何方式向该地址发起HTTP POST请求,即可实现向该群主发送消息。目前自定义机器人支持文本(text),连接(link),markdown三种消息类型。

  但是由于使用钉钉的方式是使用基于webhook的方式来扩展的,所以直接把告警消息发送到钉钉告警机器人做不到,所以需要一个转换器.

  首先有两种转换器,第一种,别人开发好的,但是消息不好自定义,另一种是自己写的,告警格式可以自定义.

 

7.4.2 现成转换器

  首先讲解github上面的项目,优点是拿过来就可以用,缺点是消息无法自定义.

  集成了这个项目,用于钉钉机器人推送告警信息https://github.com/timonwong/prometheus-webhook-dingtalk

 

  二进制部署

# 二进制包下载 
https://github.com/timonwong/prometheus-webhook-dingtalk/releases 
wget https://github.com/timonwong/prometheus-webhook-dingtalk/releases/download/v0.3.0/prometheus-webhook-dingtalk-0.3.0.linux-amd64.tar.gz 

# 启动服务 
./prometheus-webhook-dingtalk --ding.profile="webhook1=https://oapi.dingtalk.com/robot/send?access_token={替换成自己的dingding token}" 

  docker部署

docker pull timonwong/prometheus-webhook-dingtalk 

# 启动容器 
docker run -d -p 8060:8060 --name webhook timonwong/prometheus-webhook --ding.profile="webhook1=https://oapi.dingtalk.com/robot/send?access_token={替换成自己的dingding token}    

  alert配置

receivers:  
- name: webhook  
  webhook_configs:  
#主要主要就是发送的时候不是配置钉钉机器人的地址,而是转换器的地址
  - url: http://localhost:8060/dingtalk/webhook1/send    
    send_resolved: true     

7.4.3 自定义

  自定义是本人使用python的flask框架自己写的,可以自定义告警格式,以下就贴出代码

[root@prometheus01 infra]# cat /opt/dingding.py
#!/usr/bin
import os
import json
import requests
import arrow

from flask import Flask
from flask import request

app = Flask(__name__)


@app.route('/', methods=['POST', 'GET'])
def send():
    if request.method == 'POST':
        post_data = request.get_data()
        send_alert(bytes2json(post_data))
        return 'success'
    else:
        return 'weclome to use prometheus alertmanager dingtalk webhook server!'


def bytes2json(data_bytes):
    data = data_bytes.decode('utf8').replace("'", '"')
    return json.loads(data)


def send_alert(data):
    #token = os.getenv('ROBOT_TOKEN')
    #if not token:
        #print('you must set ROBOT_TOKEN env')
        #return


    import time
    now_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
    url = 'https://oapi.dingtalk.com/robot/send?access_token=e58d04a7b02ef382e5d0112ad99b413ef60774b136a2aec3fac8397b7130828a'
    tmp_data={}
    for output in data['alerts'][:]:
        #print ('----------------------------',data['alerts'])

        alert_num = int(len(data['alerts']))
        try:
            pod_name = output['labels']['pod']
        except KeyError:
            try:
                pod_name = output['labels']['pod_name']
            except KeyError:
                pod_name = 'null'

        try:
            namespace = output['labels']['namespace']
        except KeyError:
            namespace = 'null'

        try:
            container_name = output['labels']['container_name']
        except KeyError:
            container_name = 'null'

        try:
            message = output['annotations']['message']
        except KeyError:
            try:
                message = output['annotations']['description']
            except KeyError:
                message = 'null'

        try:
            hostname = output['labels']['hostname']
        except KeyError:
            hostname = 'null'

        try:
            instance = output['labels']['instance']
        except KeyError:
            instance = 'null'

        if not tmp_data:

            if pod_name != 'null':
                tmp_data = "## 告警标题: %s  (总共 %d 个告警)\n" %(output['annotations']['summary'],alert_num) +              \
                                "**任务归属**: %s \n\n" % output['labels']['job'] +                   \
                                "**告警类型**: %s \n\n" % output['labels']['alertname'] +                   \
                                "**告警级别**: %s \n\n" % output['labels']['severity'] +                    \
                                "<font color=#FF0000 >**容器名**: %s \n\n</font>" % container_name +                                           \
                                "<font color=#FF0000 >**pod名**: %s \n\n</font>" % pod_name +                                           \
                                "<font color=#FF0000 >**namespace**: %s \n\n</font>" % namespace +                                    \
                                "**告警详情**: <font color=#FF0000 >%s \n\n</font>" % message +                                             \
                                "**告警状态**: %s \n\n" % output['status'] +                                    \
                                "**触发开始时间**: %s \n\n" % arrow.get(output['startsAt']).to('Asia/Shanghai').format('YYYY-MM-DD HH:mm:ss ZZ') + "\n" \
                                "**告警发送时间**: %s \n\n" % now_time + "\n" \
                                "............................................................................................................" + "\n"
            else:
                                tmp_data = "##  告警标题: %s  (总共 %d 个告警)\n" %(output['annotations']['summary'],alert_num) +            \
                                "**任务归属**: %s \n\n" % output['labels']['job'] +                   \
                                "**告警类型**: %s \n\n" % output['labels']['alertname'] +                   \
                                "**告警级别**: %s \n\n" % output['labels']['severity'] +                    \
                                "<font color=#FF0000 >**主机名**: %s  \n\n</font>" % hostname +                    \
                                "<font color=#FF0000 >**Instance**: %s</font> \n\n" % instance  +                    \
                                "**告警详情**: <font color=#FF0000 >%s \n\n</font>" % message +                                             \
                                "**告警状态**: %s \n\n" % output['status'] +                                    \
                                "**触发时间**: %s \n\n" % arrow.get(output['startsAt']).to('Asia/Shanghai').format('YYYY-MM-DD HH:mm:ss ZZ') + "\n" \
                                "**告警发送时间**: %s \n\n" % now_time + "\n" \
                                "............................................................................................................" + "\n"

        else:
            if pod_name != 'null':
                tmp_data = tmp_data +       "**任务归属**: %s \n\n" % output['labels']['job'] +                   \
                                "**告警类型**: %s \n\n" % output['labels']['alertname'] +                   \
                                "**告警级别**: %s \n\n" % output['labels']['severity'] +                    \
                                "<font color=#FF0000 >**容器名**: %s \n\n</font>" % container_name +                                           \
                                "<font color=#FF0000 >**pod名**: %s \n\n</font>" % pod_name +                                           \
                                "<font color=#FF0000 >**namespace**: %s\n\n </font>" % namespace +                                    \
                                "**告警详情**: <font color=#FF0000 >%s \n\n</font>" % message +                                             \
                                "**告警状态**: %s \n\n" % output['status'] +                                    \
                                "**触发开始时间**: %s \n\n" % arrow.get(output['startsAt']).to('Asia/Shanghai').format('YYYY-MM-DD HH:mm:ss ZZ') + "\n" \
                                "**告警发送时间**: %s \n\n" % now_time + "\n" \
                                "............................................................................................................" + "\n"
            else:
                                tmp_data = tmp_data +      "**任务归属**: %s \n\n" % output['labels']['job'] +                   \
                                "**告警类型**: %s \n\n" % output['labels']['alertname'] +                   \
                                "**告警级别**: %s \n\n" % output['labels']['severity'] +                    \
                                "<font color=#FF0000 >**主机名**: %s  \n\n</font>" % hostname +                    \
                                "<font color=#FF0000 >**Instance**: %s \n\n</font>" % instance  +                    \
                                "**告警详情**: <font color=#FF0000 >%s \n\n</font>" % message +                                             \
                                "**告警状态**: %s \n\n" % output['status'] +                                    \
                                "**触发时间**: %s \n\n" % arrow.get(output['startsAt']).to('Asia/Shanghai').format('YYYY-MM-DD HH:mm:ss ZZ') + "\n" \
                                "**告警发送时间**: %s \n\n" % now_time + "\n" \
                                "............................................................................................................" + "\n"



    tmp_data = tmp_data + "prometheus:[http://prometheus.mobage.cn:9090](http://prometheus.mobage.cn:9090)\n\n" + \
                            "alertmanager:[http://alertmanager.mobage.cn:9093](http://alertmanager.mobage.cn:9093)\n\n"


    send_data = {
                "msgtype": "markdown",
                "markdown": {
                    "title": "sb",
                    "text": tmp_data
                }
    }

    req = requests.post(url, json=send_data)
    result = req.json()
    if result['errcode'] != 0:
      print('notify dingtalk error: %s' % result['errcode'])


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)
自定义代码

  alert配置

receivers:  
- name: webhook  
  webhook_configs:  
#主要就是发送的时候不是配置钉钉机器人的地址,而是转换器的地址
  - url: http://localhost:5000   
    send_resolved: true    

 

8.告警模版详解

  默认情况下Alertmanager使用了系统自带的默认通知模板,模板源码可以从https://github.com/prometheus/alertmanager/blob/master/template/default.tmpl获得。Alertmanager的通知模板基于Go的模板系统。Alertmanager也支持用户定义和使用自己的模板,一般来说有两种方式可以选择。

  第一种,基于模板字符串。用户可以直接在Alertmanager的配置文件中使用模板字符串,例如:

receivers:
- name: 'slack-notifications'
  slack_configs:
  - channel: '#alerts'
    text: 'https://internal.myorg.net/wiki/alerts/{{ .GroupLabels.app }}/{{ .GroupLabels.alertname }}'

  第二种方式,自定义可复用的模板文件。例如,可以创建自定义模板文件custom-template.tmpl,如下所示:

{{ define "slack.myorg.text" }}https://internal.myorg.net/wiki/alerts/{{ .GroupLabels.app }}/{{ .GroupLabels.alertname }}{{ end}}

  通过在Alertmanager的全局设置中定义templates配置来指定自定义模板的访问路径:

# Files from which custom notification template definitions are read.
# The last component may use a wildcard matcher, e.g. 'templates/*.tmpl'.
templates:
  [ - <filepath> ... ]

  在设置了自定义模板的访问路径后,用户则可以直接在配置中使用该模板:

receivers:
- name: 'slack-notifications'
  slack_configs:
  - channel: '#alerts'
    text: '{{ template "slack.myorg.text" . }}'

templates:
- '/etc/alertmanager/templates/myorg.tmpl'

9.屏蔽告警通知

  Alertmanager提供了方式可以帮助用户控制告警通知的行为,包括预先定义的抑制机制和临时定义的静默规则。

 

9.1 抑制机制

  Alertmanager的抑制机制可以避免当某种问题告警产生之后用户接收到大量由此问题导致的一系列的其它告警通知。例如当集群不可用时,用户可能只希望接收到一条告警,告诉他这时候集群出现了问题,而不是大量的如集群中的应用异常、中间件服务异常的告警通知。

  在Alertmanager配置文件中,使用inhibit_rules定义一组告警的抑制规则:

inhibit_rules:
  [ - <inhibit_rule> ... ]

  每一条抑制规则的具体配置如下:

target_match:
  [ <labelname>: <labelvalue>, ... ]
target_match_re:
  [ <labelname>: <regex>, ... ]

source_match:
  [ <labelname>: <labelvalue>, ... ]
source_match_re:
  [ <labelname>: <regex>, ... ]

[ equal: '[' <labelname>, ... ']' ]

  当已经发送的告警通知匹配到target_match和target_match_re规则,当有新的告警规则如果满足source_match或者定义的匹配规则,并且已发送的告警与新产生的告警中equal定义的标签完全相同,则启动抑制机制,新的告警不会发送。

  例如,定义如下抑制规则:

- source_match:
    alertname: NodeDown
    severity: critical
  target_match:
    severity: critical
  equal:
    - node

  例如当集群中的某一个主机节点异常宕机导致告警NodeDown被触发,同时在告警规则中定义了告警级别severity=critical。由于主机异常宕机,该主机上部署的所有服务,中间件会不可用并触发报警。根据抑制规则的定义,如果有新的告警级别为severity=critical,并且告警中标签node的值与NodeDown告警的相同,则说明新的告警是由NodeDown导致的,则启动抑制机制停止向接收器发送通知。

 

9.2 临时静默

  除了基于抑制机制可以控制告警通知的行为以外,用户或者管理员还可以直接通过Alertmanager的UI临时屏蔽特定的告警通知。通过定义标签的匹配规则(字符串或者正则表达式),如果新的告警通知满足静默规则的设置,则停止向receiver发送通知。

  进入Alertmanager UI,点击"New Silence"显示如下内容:

 

                       创建静默规则

  用户可以通过该UI定义新的静默规则的开始时间以及持续时间,通过Matchers部分可以设置多条匹配规则(字符串匹配或者正则匹配)。填写当前静默规则的创建者以及创建原因后,点击"Create"按钮即可。

  通过"Preview Alerts"可以查看预览当前匹配规则匹配到的告警信息。静默规则创建成功后,Alertmanager会开始加载该规则并且设置状态为Pending,当规则生效后则进行到Active状态。

                          活动的静默规则

  当静默规则生效以后,从Alertmanager的Alerts页面下用户将不会看到该规则匹配到的告警信息。

                           告警信息

  对于已经生效的规则,用户可以通过手动点击”Expire“按钮使当前规则过期。

 

10.使用Recoding Rules优化性能

  通过PromQL可以实时对Prometheus中采集到的样本数据进行查询,聚合以及其它各种运算操作。而在某些PromQL较为复杂且计算量较大时,直接使用PromQL可能会导致Prometheus响应超时的情况。这时需要一种能够类似于后台批处理的机制能够在后台完成这些复杂运算的计算,对于使用者而言只需要查询这些运算结果即可。Prometheus通过Recoding Rule规则支持这种后台计算的方式,可以实现对复杂查询的性能优化,提高查询效率。

 

10.1 定义Recoding rules

  在Prometheus配置文件中,通过rule_files定义recoding rule规则文件的访问路径。

rule_files:
  [ - <filepath_glob> ... ]

  每一个规则文件通过以下格式进行定义:

groups:
  [ - <rule_group> ]

  一个简单的规则文件可能是这个样子的:

groups:
  - name: example
    rules:
    - record: job:http_inprogress_requests:sum
      expr: sum(http_inprogress_requests) by (job)

  rule_group的具体配置项如下所示:

# The name of the group. Must be unique within a file.
name: <string>

# How often rules in the group are evaluated.
[ interval: <duration> | default = global.evaluation_interval ]

rules:
  [ - <rule> ... ]

  与告警规则一致,一个group下可以包含多条规则rule。

# The name of the time series to output to. Must be a valid metric name.
record: <string>

# The PromQL expression to evaluate. Every evaluation cycle this is
# evaluated at the current time, and the result recorded as a new set of
# time series with the metric name as given by 'record'.
expr: <string>

# Labels to add or overwrite before storing the result.
labels:
  [ <labelname>: <labelvalue> ]

  根据规则中的定义,Prometheus会在后台完成expr中定义的PromQL表达式计算,并且将计算结果保存到新的时间序列record中。同时还可以通过labels为这些样本添加额外的标签。

  这些规则文件的计算频率与告警规则计算频率一致,都通过global.evaluation_interval定义:

global:
  [ evaluation_interval: <duration> | default = 1m ]

作者:小家电维修

相见有时,后会无期。

原文地址:https://www.cnblogs.com/lizexiong/p/15579527.html