prometheus+alertmanager+webhook实现自定义监控报警系统

1.概述

上一篇文章prometheus+grafana+mtail+node_exporter实现机器负载及业务监控介绍了使用mtail和node_exporter实现的prometheus无埋点监控机器负载和业务的监控系统,本文是在其基础上实现自定义报警功能。
Prometheus+Alertmanager 的警报分为两个部分:

  • Prometheus负责中配置警报规则,将警报发送到Alertmanager
  • Alertmanager 负责管理这些警报,包括沉默,抑制,合并和发送通知

Alertmanager 发送通知有多种方式,其内部集成了邮箱、Slack、企业微信等三种方式,也提供了webhook的方式来扩展报警通知方式,网上也有大量例子实现对第三方软件的集成,如钉钉等。本文介绍邮件报警方式和通过使用java来搭建webhook自定义通知报警的方式。

本文内容主要分为四块:

  • prometheus报警规则配置
  • alertmanager配置及部署
  • 关联prometheus和alertmanager
  • 配置报警通知方式

2.prometheus配置报警规则

prometheus.yml属性配置

属性描述
scrape_interval样本采集周期,默认为1分钟采集一次
evaluation_interval告警规则计算周期,默认为1分钟计算一次
rule_files指定告警规则的文件
scrape_configsjob的配置项,里面可配多组job任务
job_name任务名称,需要唯一性
static_configsjob_name的配置选项,一般使用file_sd_configs 热加载配置
file_sd_configsjob_name的动态配置选项,使用此配置可以实现配置文件的热加载
files:file_sd_configs配置的服务发现的文件路径列表,支持.json,.yml或.yaml,路径最后一层支持通配符*
refresh_intervalfile_sd_configs中的files重新加载的周期,默认5分钟

此处我们使用rule_files属性来设置告警文件

# my global config
global:
  scrape_interval:     15s # 采样周期
  evaluation_interval: 15s # 告警规则计算周期

# Alertmanager configuration
alerting:
  alertmanagers:
  - static_configs:
    - targets:
      # - alertmanager:9093

# 报警规则文件可以指定多个,并且可以使用通配符*
rule_files:
  - "rules/*_rules.yml"
  # - "second_rules.yml"

# 采集job配置
scrape_configs:
  - job_name: 'prometheus'
    #使用file_sd_configs热加载配置文件
    file_sd_configs:
      #指定1分钟加载一次配置
    - refresh_interval: 1m
      files:
      - config_prometheus.json
  
  - job_name: 'linux_base'
    file_sd_configs:
    - refresh_interval: 1m
      files:
      - config_exporter.json
      
  - job_name: 'service_base'
    file_sd_configs:
    - refresh_interval: 1m
      files:
      - config_mtail.json
      
  - job_name: 'grafana'
    file_sd_configs:
    - refresh_interval: 1m
      files:
      - config_grafana.json


设置报警规则,rules/host_rules.yml

groups:
# 报警组组名称
- name: hostStatsAlert
  #报警组规则
  rules:
   #告警名称,需唯一
  - alert: hostCpuUsageAlert
    #promQL表达式
    expr: sum(avg without (cpu)(irate(node_cpu_seconds_total{mode!='idle'}[5m]))) by (instance) > 0.85
    #满足此表达式持续时间超过for规定的时间才会触发此报警
    for: 1m
    labels:
      #严重级别
      severity: page
    annotations:
     #发出的告警标题
      summary: "实例 {{ $labels.instance }} CPU 使用率过高"
      #发出的告警内容
      description: "实例{{ $labels.instance }} CPU 使用率超过 85% (当前值为: {{ $value }})"
  - alert: hostMemUsageAlert
    expr: (node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes)/node_memory_MemTotal_bytes > 0.85
    for: 1m
    labels:
      severity: page
    annotations:
      summary: "实例 {{ $labels.instance }} 内存使用率过高"
      description: "实例 {{ $labels.instance }} 内存使用率 85% (当前值为: {{ $value }})"

采集任务job配置config_exporter.json配置如下(其他job配置文件类似):

[
  {
    "targets": [ "192.168.113.13:9100"],
    "labels": {
      "env": "prod"
    }
  },
  {
    "targets": [ "10.12.141.150:9100"],
    "labels": {
      "env": "local"
    }
  },
  {
    "targets": [ "10.12.141.151:9100"],
    "labels": {
      "env": "local2"
    }
  }

]

配置完报警规则重启prometheus,访问http://ip:9090/,点击alerts就能看到配置的报警信息了,如下:
在这里插入图片描述

3.alertmanager配置及部署

3.1.alertmanager配置

alertmanager会定义一个基于标签匹配规则的路由树,用以接收到报警后根据不同的标签匹配不同的路由,来将报警发送给不同的receiver。如果定义一个路由route则需要接收并处理所有的报警,如果需要区分不同的报警发送给不同的receiver,则需要配置多个子级route来处理不同的报警,而根route此时必须能够接收处理所有的报警。

#根路由
route:
  #顶级路由配置的接收者(匹配不到子级路由,会使用根路由发送报警)
  receiver: 'default-receiver'
  #设置等待时间,在此等待时间内如果接收到多个报警,则会合并成一个通知发送给receiver
  group_wait: 30s
  #两次报警通知的时间间隔,如:5m,表示发送报警通知后,如果5分钟内再次接收到报警则不会发送通知
  group_interval: 5m
  #发送相同告警的时间间隔,如:4h,表示4小时内不会发送相同的报警
  repeat_interval: 4h
  #分组规则,如果满足group_by中包含的标签,则这些报警会合并为一个通知发给receiver
  group_by: [cluster, alertname]
  routes:
  #子路由的接收者
  - receiver: 'database-pager'
    group_wait: 10s
    #默认为false。false:配置到满足条件的子节点点后直接返回,true:匹配到子节点后还会继续遍历后续子节点
    continue:false
    #正则匹配,验证当前标签service的值是否满足当前正则的条件
    match_re:
      service: mysql|cassandra
  #子路由的接收者
  - receiver: 'frontend-pager'
    group_by: [product, environment]
    #字符串匹配,匹配当前标签team的值为frontend的报警
    match:
      team: frontend

#定义所有接收者
receivers:
#接收者名称
- name: 'default-receiver'
  #接收者为webhook类型
  webhook_configs:
  #webhook的接收地址
  - url: 'http://127.0.0.1:5001/'
- name: 'database-pager'
  webhook_configs:
  - url: 'http://127.0.0.1:5002/'
- name: 'frontend-pager'
  webhook_configs:
  - url: 'http://127.0.0.1:5003/'

3.2.alertmanager部署

建议下载最新版本,最新版下载地址请戳此处(可能需要翻墙),我使用的版本为alertmanager-0.20.0.linux-amd64.tar.gz,我的版本csdn下载地址请戳
将其解压到/usr/local后,进入目录/usr/local/alertmanager-0.20.0.linux-amd64,会有个默认配置文件: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']

使用默认配置在后台启动:

nohup ./alertmanager > alertmanager.out 2>&1 &

查看是否启动成功:

ps -ef | grep alertmanager 

启动后访问http://ip:9093/查看是否启动成功,点击status查看alertmanager及其配置,访问如下(我的配置有改动,请以自己页面展示为准):
在这里插入图片描述

4.prometheus关联alertmanager

prometheus.yml中的alerting标签下配置上alertmanager的地址即可,配置如下:

# Alertmanager configuration
alerting:
  alertmanagers:
  - static_configs:
    - targets: ['192.168.199.23:9093']

添加后重启prometheus即可。

5.配置报警通知方式

5.1.alertmanager邮箱报警demo

global:
  #超时时间
  resolve_timeout: 5m
  #smtp地址需要加端口
  smtp_smarthost: 'smtp.126.com:25'
  smtp_from: 'xxx@126.com'
  #发件人邮箱账号
  smtp_auth_username: 'xxx@126.com'
  #账号对应的授权码(不是密码),阿里云个人版邮箱目前好像没有授权码,126邮箱授权码可以在“设置”里面找到
  smtp_auth_password: '1qaz2wsx'
  smtp_require_tls: false

route:
  group_by: ['alertname']
  group_wait: 10s
  group_interval: 1m
  repeat_interval: 4h
  receiver: 'mail'
receivers:
- name: 'mail'
  email_configs:
  - to: 'xxx@aliyun.com'

设置后如果有通知,即可收到邮件如下:
在这里插入图片描述

5.2.alertmanager使用webhook(java)报警demo

global:
  resolve_timeout: 5m

route:
  group_by: ['alertname']
  group_wait: 10s
  group_interval: 1m
  repeat_interval: 4h
  receiver: 'webhook'
receivers:
- name: 'webhook'
  webhook_configs:
    - url: 'http://192.168.199.152/demo'

使用webhook方式,alertmanager会给配置的webhook地址发送一个http类型的post请求,参数为json字符串(字符串类型),如下(此处格式化为json了):

{
    "receiver":"webhook",
    "status":"resolved",
    "alerts":[
        {
            "status":"resolved",
            "labels":{
                "alertname":"hostCpuUsageAlert",
                "instance":"192.168.199.24:9100",
                "severity":"page"
            },
            "annotations":{
                "description":"192.168.199.24:9100 CPU 使用率超过 85% (当前值为: 0.9973333333333395)",
                "summary":"机器 192.168.199.24:9100 CPU 使用率过高"
            },
            "startsAt":"2020-02-29T19:45:21.799548092+08:00",
            "endsAt":"2020-02-29T19:49:21.799548092+08:00",
            "generatorURL":"http://localhost.localdomain:9090/graph?g0.expr=sum+by%28instance%29+%28avg+without%28cpu%29+%28irate%28node_cpu_seconds_total%7Bmode%21%3D%22idle%22%7D%5B5m%5D%29%29%29+%3E+0.85&g0.tab=1",
            "fingerprint":"368e9616d542ab48"
        }
    ],
    "groupLabels":{
        "alertname":"hostCpuUsageAlert"
    },
    "commonLabels":{
        "alertname":"hostCpuUsageAlert",
        "instance":"192.168.199.24:9100",
        "severity":"page"
    },
    "commonAnnotations":{
        "description":"192.168.199.24:9100 CPU 使用率超过 85% (当前值为: 0.9973333333333395)",
        "summary":"机器 192.168.199.24:9100 CPU 使用率过高"
    },
    "externalURL":"http://localhost.localdomain:9093",
    "version":"4",
    "groupKey":"{}:{alertname="hostCpuUsageAlert"}"
}

此时需要使用java(其他任何语言都可以,反正只要能处理http的请求就行)搭建个http的请求处理器来处理报警通知,如下:

package com.demo.demo1.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@Slf4j
@Controller
@RequestMapping("/")
public class AlertController {


    @RequestMapping(value = "/demo", produces = "application/json;charset=UTF-8")
    @ResponseBody
    public String pstn(@RequestBody String json) {
        log.debug("alert notify  params: {}", json);
        Map<String, Object> result = new HashMap<>();
        result.put("msg", "报警失败");
        result.put("code", 0);

        if(StringUtils.isBlank(json)){
            return JSON.toJSONString(result);
        }
        JSONObject jo = JSON.parseObject(json);

        JSONObject commonAnnotations = jo.getJSONObject("commonAnnotations");
        String status = jo.getString("status");
        if (commonAnnotations == null) {
            return JSON.toJSONString(result);
        }


        String subject = commonAnnotations.getString("summary");
        String content = commonAnnotations.getString("description");
        List<String> emailusers = new ArrayList<>();
        emailusers.add("xxx@aliyun.com");

        List<String> users = new ArrayList<>();
        users.add("158*****5043");


        try {
            boolean success = Util.email(subject, content, emailusers);
            if (success) {
                result.put("msg", "报警成功");
                result.put("code", 1);
            }
        } catch (Exception e) {
            log.error("=alert email notify error. json={}", json, e);
        }
        try {
            boolean success = Util.sms(subject, content, users);
            if (success) {
                result.put("msg", "报警成功");
                result.put("code", 1);
            }
        } catch (Exception e) {
            log.error("=alert sms notify error. json={}", json, e);
        }


        return JSON.toJSONString(result);
    }

}

6.总结

alertmanager配置功能确认很强大,完全能够按照自己的目标定义灵活的通知和报警方式,尤其是对webhook的支持,简直不能更灵活了。而且alertmanager还支持定义template来更清晰的彰显要通知的内容。但是本人还没有发现alertmanager该怎么进行配置的热加载,后面还要再研究下怎么优化通知,避免告警轰炸和提高告警的准确性。

<think>好的,用户现在想了解Alertmanager自定义报警模板,之前他们问过关于Alertmanager主配置和CRD参数命名差异的问题,现在可能是在深入配置Alertmanager时需要定制通知内容。首先,我需要确定用户对Alertmanager的基本使用是否熟悉,但根据之前的问题,可能已经有一定的了解。 用户的需求可能是希望自定义报警通知的格式,使其更符合团队的需求,比如添加更多详细信息、调整结构或集成特定工具的消息格式。他们可能遇到了默认模板信息不够详细或者格式不符合需求的问题。 接下来,我需要考虑Alertmanager模板的工作原理。它基于Go的模板引擎,所以用户可能需要了解一些模板语法的基础知识。同时,模板文件的位置、如何引用以及常用函数都是关键点。 需要分步骤解释如何创建自定义模板,包括模板文件的结构、常用变量、函数以及示例。可能还需要提到调试方法,因为编写模板时容易出错。另外,结合之前的CRD配置问题,如果用户使用Kubernetes,可能需要说明如何在AlertmanagerConfig CRD中引用模板,这可能会涉及ConfigMap的创建和挂载。 还要注意用户可能的常见错误,比如语法错误、路径配置不正确或者变量使用不当。给出一个具体的示例模板,展示如何结构化报警信息,并说明如何在配置中启用这个模板。 最后,确保回答结构清晰,步骤明确,提供实用建议和示例,帮助用户逐步实现自定义模板,避免之前提到的参数命名差异带来的混淆。可能还需要提醒用户检查版本兼容性,确保使用的函数和变量与他们的Alertmanager版本一致。</think>--- ### Alertmanager 自定义报警模板详解 Alertmanager自定义报警模板(Notification Template)允许用户**完全控制报警通知的格式和内容**,可适配企业内部的监控需求(如生成符合钉钉、企业微信或自定义Webhook要求的消息结构)。以下是实现模板自定义的核心要点: --- #### 一、模板基础机制 1. **底层技术** 基于 [Go 模板引擎](https://golang.org/pkg/text/template/),支持条件判断、循环、函数调用等逻辑。 2. **数据源结构** 模板处理的数据对象为 [`Data` 结构体](https://github.com/prometheus/alertmanager/blob/main/template/template.go#L43),包含以下关键字段: ```go type Data struct { Receiver string Status string // firing/resolved Alerts []*Alert // 所有报警对象 GroupLabels KV // 分组标签 CommonLabels KV // 所有报警的共有标签 CommonAnnotations KV // 所有报警的共有注释 ExternalURL string // Alertmanager外部访问地址 } ``` --- #### 二、模板创建步骤 1. **创建模板文件** 建议使用 `.tmpl` 后缀,例如 `custom_template.tmpl`,内容示例: ```gotemplate {{ define "slack.custom.message" }} {{- if eq .Status "firing" }}🚨 报警触发 🚨{{ else }}✅ 报警恢复 ✅{{ end }} *[{{ .Status | toUpper }}]* 分组: {{ .GroupLabels.SortedPairs.Values | join ", " }} {{ range .Alerts }} 🔍 **{{ .Labels.alertname }}** ({{ .Labels.severity }}) 📌 实例: {{ .Labels.instance }} 🕒 时间: {{ .StartsAt.Format "2006-01-02 15:04:05" }} {{- if .Annotations.summary }} 📄 摘要: {{ .Annotations.summary }} {{- end }} {{- if .Annotations.description }} 📝 详情: {{ .Annotations.description }} {{- end }} {{- end }} {{ end }} ``` 2. **配置 Alertmanager 引用模板** 在主配置文件 `alertmanager.yml` 中指定模板路径: ```yaml templates: - '/etc/alertmanager/templates/*.tmpl' # Kubernetes中需挂载为ConfigMap ``` 3. **在路由中指定模板名称** ```yaml receivers: - name: 'slack-webhook' slack_configs: - channel: '#alerts' title: '{{ template "slack.custom.message" . }}' # 引用模板定义 send_resolved: true ``` --- #### 三、核心功能详解 ##### 1. 模板函数库 Alertmanager 扩展了以下常用函数: | 函数 | 用途 | 示例 | |-----------------------|---------------------------------|------------------------------| | `toUpper`/`toLower` | 大小写转换 | `{{ .Status | toUpper }}` | | `title` | 首字母大写 | `{{ "hello" | title }}` → "Hello" | | `match`/`regexMatch` | 正则匹配 | `{{ if match "prod.*" .Labels.env }}` | | `join` | 字符串拼接 | `{{ .GroupLabels | join "," }}` | | `safeHtml` | 防止HTML转义 | `{{ .Annotations.desc | safeHtml }}` | ##### 2. 条件控制逻辑 ```gotemplate {{ if gt (len .Alerts) 5 }} ⚠️ 注意:当前分组包含超过5条报警! {{ else if gt (len .Alerts) 1 }} ❗ 多个报警同时触发 {{ else }} 单个报警事件 {{ end }} ``` ##### 3. 循环处理报警列表 ```gotemplate {{ range $index, $alert := .Alerts }} 报警 #{{ add $index 1 }}: - 名称: {{ $alert.Labels.alertname }} - 触发时间: {{ $alert.StartsAt.Format "2006-01-02 15:04:05" }} {{ if $alert.Annotations.runbook }}运维手册: {{ $alert.Annotations.runbook }}{{ end }} {{ end }} ``` --- #### 四、Kubernetes 环境最佳实践 1. **通过 ConfigMap 挂载模板** ```yaml # alertmanager-templates-cm.yaml apiVersion: v1 kind: ConfigMap metadata: name: alertmanager-templates namespace: monitoring data: custom_template.tmpl: | {{ define "custom.message" }}...{{ end }} ``` 2. **Alertmanager 部署配置** ```yaml spec: template: spec: containers: - name: alertmanager volumeMounts: - name: alertmanager-templates mountPath: /etc/alertmanager/templates/ volumes: - name: alertmanager-templates configMap: name: alertmanager-templates ``` --- #### 五、调试技巧 1. **本地测试工具** 使用 [`amtool`](https://github.com/prometheus/alertmanager#amtool) 模拟模板渲染: ```bash amtool check-template custom_template.tmpl ``` 2. **查看最终配置** 在 Kubernetes 中验证配置是否正确加载: ```bash kubectl -n monitoring exec alertmanager-pod-id -- ls /etc/alertmanager/templates/ ``` 3. **日志排查** 开启调试日志观察模板加载过程: ```yaml spec: logLevel: debug # 在Alertmanager配置中设置 ``` --- #### 六、典型模板示例(适配企业微信) ```gotemplate {{ define "wechat.markdown" }} {{- if eq .Status "firing" }}<font color="warning">报警触发</font>{{ else }}<font color="info">报警恢复</font>{{ end -}} > **状态**: {{ .Status | toUpper }} > **分组标签**: {{ range $k, $v := .GroupLabels }}{{ $k }}={{ $v }} {{ end }} {{ range .Alerts }} {{- if eq .Status "firing" }} ### 🔥 {{ .Labels.alertname }} ({{ .Labels.severity }}) {{- else }} ### 🌿 {{ .Labels.alertname }} 已恢复 {{- end }} - 实例: {{ .Labels.instance }} - 触发时间: {{ .StartsAt.Format "2006-01-02 15:04:05" }} {{- if .Annotations.summary }} - 摘要: {{ .Annotations.summary }} {{- end }} {{- end }} {{ end }} ``` --- 通过自定义模板,可以实现以下高级功能: - 根据报警严重性显示不同颜色标记 - 自动附加运维手册链接 - 生成符合团队协作工具要求的Markdown/HTML格式 - 对重复报警进行合并展示 - 添加静默策略参考链接 建议在开发过程中使用小型测试报警验证模板逻辑,逐步完善通知内容。
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值