跳到主要内容

报警接收器

Alertmanager 支持很多内置的报警接收器,如 email、slack、企业微信、webhook 等,上面的测试我们使用的 email 来接收报警。

通知模板

告警通知使用的是默认模版,因为它已经编译到二进制包了,所以我们不需要额外配置。如果我们想自定义模版,这又该如何配置呢?

Alertmanager 默认使用的通知模板可以从 https://github.com/prometheus/alertmanager/blob/master/template/default.tmpl 获取,Alertmanager 的通知模板是基于 Golang 的模板系统,当然也支持用户自定义和使用自己的模板。

第一种方式是基于模板字符串,直接在 Alertmanager 的配置文件中使用模板字符串,如下所示:

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

直接在配置文件中可以使用一些模板字符串,比如获取 {{ .GroupLabels }} 下面的一些属性。

另外一种方法就是直接修改官方默认的模板,此外也可以自定义可复用的模板文件,比如针对 email 的模板,我们可以创建一个名为 template_email.tmpl 的自定义模板文件,如下所示:

apiVersion: v1
kind: ConfigMap
metadata:
name: alert-config
namespace: kube-mon
data:
config.yml: |-
global: # 全局配置
......
route: # 路由
......
templates: # 增加 templates 配置,指定模板文件
- '/etc/alertmanager/template_email.tmpl'

receivers: # 接收器
- name: 'email'
email_configs:
- to: '517554016@qq.com'
send_resolved: true
html: '{{ template "email.html" . }}' # 此处通过 html 指定模板文件中定义的 email.html 模板

# 下面定义 email.html 必须和上面指定的一致,注释不能写进模板文件中
template_email.tmpl: |-
{{ define "email.html" }}
{{- if gt (len .Alerts.Firing) 0 -}}{{ range .Alerts }}
@报警<br>
<strong>实例:</strong> {{ .Labels.instance }}<br>
<strong>概述:</strong> {{ .Annotations.summary }}<br>
<strong>详情:</strong> {{ .Annotations.description }}<br>
<strong>时间:</strong> {{ (.StartsAt.Add 28800e9).Format "2006-01-02 15:04:05" }}<br>
{{ end }}{{ end -}}<br>
{{- if gt (len .Alerts.Resolved) 0 -}}{{ range .Alerts }}<br>
@恢复<br>
<strong>实例:</strong> {{ .Labels.instance }}<br>
<strong>信息:</strong> {{ .Annotations.summary }}<br>
<strong>恢复:</strong> {{ (.StartsAt.Add 28800e9).Format "2006-01-02 15:04:05" }}<br>
{{ end }}{{ end -}}
{{- end }}

在 Alertmanager 配置中通过 templates 属性来指定我们自定义的模板路径,这里我们定义的 template_email.tmpl 模板会通过 Configmap 挂载到 /etc/alertmanager 路径下,模板中通过 {{ define "email.html" }} 定义了一个名为 email.html 的命名模板,然后在 email 的接收器中通过 email_configs.html 来指定定义的命名模板即可。更新上面 Alertmanager 的配置对象,重启 Alertmanager 服务,然后等待告警发出,即可看到我们如下所示自定义的模板信息:

自定义模板

WebHook 接收器

上面我们配置的是 AlertManager 自带的邮件报警模板,我们也说了 AlertManager 支持很多中报警接收器,比如 slack、微信之类的,其中最为灵活的方式当然是使用 webhook 了,我们可以定义一个 webhook 来接收报警信息,然后在 webhook 里面去进行处理,需要发送怎样的报警信息我们自定义就可以,下面的 JSON 数据就是 AlertManager 将报警信息 POST 给 webhook 的数据:

{
"receiver": "webhook",
"status": "firing",
"alerts": [
{
"status": "firing",
"labels": {
"alertname": "NodeMemoryUsage",
"beta_kubernetes_io_arch": "amd64",
"beta_kubernetes_io_os": "linux",
"instance": "node1",
"job": "nodes",
"kubernetes_io_arch": "amd64",
"kubernetes_io_hostname": "node1",
"kubernetes_io_os": "linux",
"team": "node"
},
"annotations": {
"description": "node1: Memory usage is above 30% (current value is: 42.097619438581596)",
"summary": "node1: High Memory usage detected"
},
"startsAt": "2022-03-02T02:13:19.69Z",
"endsAt": "0001-01-01T00:00:00Z",
"generatorURL": "http://prometheus-649968556c-8p4tj:9090/graph?g0.expr=%28node_memory_MemTotal_bytes+-+%28node_memory_MemFree_bytes+%2B+node_memory_Buffers_bytes+%2B+node_memory_Cached_bytes%29%29+%2F+node_memory_MemTotal_bytes+%2A+100+%3E+30\u0026g0.tab=1",
"fingerprint": "8cc4749f998d64dd"
}
],
"groupLabels": { "instance": "node1" },
"commonLabels": {
"alertname": "NodeMemoryUsage",
"beta_kubernetes_io_arch": "amd64",
"beta_kubernetes_io_os": "linux",
"instance": "node1",
"job": "nodes",
"kubernetes_io_arch": "amd64",
"kubernetes_io_hostname": "node1",
"kubernetes_io_os": "linux",
"team": "node"
},
"commonAnnotations": {
"description": "node1: Memory usage is above 30% (current value is: 42.097619438581596)",
"summary": "node1: High Memory usage detected"
},
"externalURL": "http://alertmanager-5774d6f5f4-prdgr:9093",
"version": "4",
"groupKey": "{}/{team=\"node\"}:{instance=\"node1\"}",
"truncatedAlerts": 0
}

我这里实现了一个简单的 webhook 程序,代码仓库地址:https://github.com/cnych/promoter,该程序支持在消息通知中显示报警图表。

首先在钉钉群中选择创建一个自定义的机器人:

创建机器人

这里我们选择添加额外密钥的方式来验证机器人,其他两种方式可以忽略,需要记住该值,下面会使用:

密钥

创建完成后会提供一个 webhook 的地址,该地址会带一个 acess_token 的参数,该参数下面也会使用:

webhook 地址

接下来我们需要将 webhook 服务部署到集群中,对应的资源清单如下:

# promoter.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: promoter-conf
namespace: kube-mon
data:
config.yaml: |
global:
prometheus_url: http://192.168.31.31:30104
wechat_api_secret: <secret> # 企业微信 secret
wechat_api_corp_id: <corp_id> # 企业微信 corp_id
dingtalk_api_token: <token> # 钉钉机器人 token
dingtalk_api_secret: <secret> # 钉钉机器人 secret

s3:
access_key: <ak>
secret_key: <sk>
endpoint: oss-cn-beijing.aliyuncs.com
region: cn-beijing
bucket: my-oss-testing

receivers:
- name: test1
wechat_configs:
- agent_id: <agent_id>
to_user: "@all"
message_type: markdown
dingtalk_configs:
- message_type: markdown
at:
isAtAll: true
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: promoter
namespace: kube-mon
labels:
app: promoter
spec:
selector:
matchLabels:
app: promoter
template:
metadata:
labels:
app: promoter
spec:
volumes:
- name: promotercfg
configMap:
name: promoter-conf
containers:
- name: promoter
image: cnych/promoter:main
imagePullPolicy: IfNotPresent
args:
- '--config.file=/etc/promoter/config.yaml'
ports:
- containerPort: 8080
volumeMounts:
- mountPath: '/etc/promoter'
name: promotercfg
---
apiVersion: v1
kind: Service
metadata:
name: promoter
namespace: kube-mon
labels:
app: promoter
spec:
selector:
app: promoter
ports:
- port: 8080

配置完成后,直接创建上面的资源对象即可:

☸ ➜ kubectl apply -f promoter.yaml
☸ ➜ kubectl get pods -n kube-mon -l app=promoter
NAME READY STATUS RESTARTS AGE
promoter-67c5795c4c-7mlvq 1/1 Running 3 (34m ago) 3d16h

部署成功后,现在我们就可以给 AlertManager 配置一个 webhook 了,在上面的配置中增加一个路由接收器

  routes:
- receiver: webhook
group_wait: 10s
group_by: ['instance']
match:
team: node
receivers:
- name: 'webhook'
webhook_configs:
- url: 'http://promoter:8080/test1/send'
send_resolved: true

我们这里配置了一个名为 webhook 的接收器,地址为:http://promoter:8080/test1/send,这个地址当然就是上面我们部署的钉钉的 webhook 的接收程序的 Service 地址。

然后我们可以更新 AlertManager 和 Prometheus 的 ConfigMap 资源对象,更新完成后,隔一会儿执行 reload 操作是更新生效,如果有报警触发的话,隔一会儿关于这个节点文件系统的报警就会被触发了,由于这个报警信息包含一个team=node 的 label 标签,所以会被路由到 webhook 这个接收器中,也就是上面我们自定义的这个 webhook,触发后可以观察这个 Pod 的日志:

☸ ➜ kubectl logs -f promoter-5dbd47798c-bnjqm -n kube-mon
ts=2022-03-07T01:38:08.001Z caller=main.go:58 level=info msg="Staring Promoter" version="(version=0.2.3, branch=HEAD, revision=0a9cf8fc9bd55d1d2d47d181867135914927c2fc)"
ts=2022-03-07T01:38:08.001Z caller=main.go:59 level=info build_context="(go=go1.17.8, user=root@91adc4eacff7, date=20220305-05:40:54)"
ts=2022-03-07T01:38:08.001Z caller=main.go:127 level=info component=configuration msg="Loading configuration file" file=/etc/promoter/config.yaml
ts=2022-03-07T01:38:08.002Z caller=main.go:138 level=info component=configuration msg="Completed loading of configuration file" file=/etc/promoter/config.yaml
ts=2022-03-07T01:38:08.003Z caller=main.go:88 level=info msg=Listening address=:808

可以看到 POST 请求已经成功了,同时这个时候正常来说就可以收到一条钉钉消息了:

dingtalk 消息

如果想同时给企业微信发送消息通知,则需要在上面的 Webhook 配置中增加企业微信相关的配置。首先在企业微信后台创建一个新的应用,用来接收消息通知:

创建应用

创建完成后即可以获取 AgentId 值和 Secret 值,Secret 值就是 global.wechat_api_secret,AgentId 是 wechat_config.agent_id 的值:

应用配置

还有一个全局的企业 ID 值 global.wechat_api_corp_id 位于 我的企业 -> 企业信息 最下方的企业 ID。配置完成后可以和钉钉放在同一个 receiver 中,这样就可以同时给钉钉和企业微信发送消息了,也可以单独配置一个 receiver,但是这样需要单独配置一个 webhook 地址。

企业微信消息

但是需要注意企业微信 markdown 不支持直接显示图片,所以我们可以单独为企业微信配置模板,不渲染图片即可。