Kubernetes集群监控之alertmanager

[toc]

参考

简介

Alertmanager 主要用于接收 Prometheus 发送的告警信息,它支持丰富的告警通知渠道,而且很容易做到告警信息进行去重,降噪,分组等,是一款前卫的告警通知系统。

image

image

配置部署

主要步骤

一、部署Alertmanager
二、配置Prometheus与Alertmanager通信
三、配置告警
  1. prometheus指定rules目录
  2. configmap存储告警规则
  3. configmap挂载到容器rules目录

部署alertmanager

alertmanager-deploy.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: alertmanager
namespace: monitoring
spec:
replicas: 1
selector:
matchLabels:
k8s-app: alertmanager
template:
metadata:
labels:
k8s-app: alertmanager
spec:
containers:
- image: prom/alertmanager:v0.19.0
name: alertmanager
args:
- "--config.file=/etc/alertmanager/config/alertmanager.yml"
- "--storage.path=/alertmanager"
- "--data.retention=720h"
volumeMounts:
- mountPath: "/alertmanager"
name: data
- mountPath: "/etc/alertmanager/config"
name: config-volume
- mountPath: "/etc/alertmanager/template"
name: alertmanager-tmpl
resources:
requests:
cpu: 50m
memory: 500Mi
limits:
cpu: 100m
memory: 1Gi
volumes:
- name: data
emptyDir: {}
- name: config-volume
configMap:
name: alertmanager-config
- name: alertmanager-tmpl
configMap:
name: alertmanager-tmpl

alertmanager-svc.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: v1
kind: Service
metadata:
name: alertmanager
namespace: monitoring
labels:
k8s-app: alertmanager
annotations:
prometheus.io/scrape: 'true'
spec:
ports:
- name: web
port: 9093
targetPort: 9093
protocol: TCP
nodePort: 30027
type: NodePort
selector:
k8s-app: alertmanager

alertmanager-config.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
apiVersion: v1
kind: ConfigMap
metadata:
name: alertmanager-config
namespace: monitoring
data:
alertmanager.yml: |
global:
resolve_timeout: 1m
wechat_api_corp_id: '*****'
wechat_api_url: '*****'
wechat_api_secret: '*****'
smtp_smarthost: '*****'
smtp_from: '****'
smtp_auth_username: '****'
smtp_auth_password: '****'
smtp_require_tls: true

templates:
- '/etc/alertmanager/template/*.tmpl'

route:
group_by: ['alertname', 'job']
group_wait: 20s
group_interval: 20s
repeat_interval: 2m
receiver: 'email'
routes:
- receiver: "email"
group_wait: 10s
continue: true
match_re:
severity: critical|error|warning
#- receiver: "wechat"
#group_wait: 10s
#continue: true
#match_re:
#severity: critical|error|warning

receivers:
#- name: "wechat"
#wechat_configs:
#- send_resolved: true
#to_party: '1'
#agent_id: 1000003
#corp_id: '****'
#api_url: '****'
#api_secret: '****'
- name: "email"
email_configs:
- to: '****'
send_resolved: true

inhibit_rules:
- source_match:
severity: 'critical'
target_match:
severity: 'error'
equal: ['alertname']

alertmanager-tmpl.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
apiVersion: v1
kind: ConfigMap
metadata:
name: alertmanager-tmpl
namespace: monitoring
data:
wechat.tmpl: |
{{ define "wechat.default.message" }}
{{- if gt (len .Alerts.Firing) 0 -}}{{ range .Alerts }}
@警报
状态: {{ .Status }}
名称: {{ .Labels.alertname }}
级别: {{ .Labels.severity }}
实例: {{ .Labels.instance }}
信息: {{ .Annotations.summary }}
详情: {{ .Annotations.description }}
时间: {{ .StartsAt.Format "2006-01-02 15:04:05" }}
{{ end }}{{ end -}}
{{- if gt (len .Alerts.Resolved) 0 -}}{{ range .Alerts }}
@恢复
状态: {{ .Status }}
名称: {{ .Labels.alertname }}
级别: {{ .Labels.severity }}
实例: {{ .Labels.instance }}
信息: {{ .Annotations.summary }}
详情: {{ .Annotations.description }}
时间: {{ .StartsAt.Format "2006-01-02 15:04:05" }}
恢复: {{ .EndsAt.Format "2006-01-02 15:04:05" }}
{{ end }}{{ end -}}
{{- end }}
email.tmpl: |
{{ define "email.default.html" }}
{{- if gt (len .Alerts.Firing) 0 -}}{{ range .Alerts }}
@警报
状态: {{ .Status }}
名称: {{ .Labels.alertname }}
级别: {{ .Labels.severity }}
实例: {{ .Labels.instance }}
信息: {{ .Annotations.summary }}
详情: {{ .Annotations.description }}
时间: {{ .StartsAt.Format "2006-01-02 15:04:05" }}
{{ end }}{{ end -}}
{{- if gt (len .Alerts.Resolved) 0 -}}{{ range .Alerts }}
@恢复
状态: {{ .Status }}
名称: {{ .Labels.alertname }}
级别: {{ .Labels.severity }}
实例: {{ .Labels.instance }}
信息: {{ .Annotations.summary }}
详情: {{ .Annotations.description }}
时间: {{ .StartsAt.Format "2006-01-02 15:04:05" }}
恢复: {{ .EndsAt.Format "2006-01-02 15:04:05" }}
{{ end }}{{ end -}}
{{ end }}

部署之后通过IP:9093访问alertmanager UI界面

在这个页面中我们可以进行一些操作,比如过滤、分组等等,里面还有两个新的概念:Inhibition(抑制)和 Silences(静默)。

  • Inhibition:如果某些其他警报已经触发了,则对于某些警报,Inhibition 是一个抑制通知的概念。例如:一个警报已经触发,它正在通知整个集群是不可达的时,Alertmanager 则可以配置成关心这个集群的其他警报无效。这可以防止与实际问题无关的数百或数千个触发警报的通知,Inhibition 需要通过上面的配置文件进行配置。
  • Silences:静默是一个非常简单的方法,可以在给定时间内简单地忽略所有警报。Silences 基于 matchers配置,类似路由树。来到的警告将会被检查,判断它们是否和活跃的 Silences 相等或者正则表达式匹配。如果匹配成功,则不会将这些警报发送给接收者。

配置Prometheus与alertmanager通信

编辑 prometheus-configmap.yaml 配置文件添加绑定信息

最后的alert模块修改一下,之前的都注释

1
2
3
4
alerting:
alertmanagers:
- static_configs:
- targets: ["alertmanager:80"] ####需要修改alertmanger服务名字,集群内部通过服务名调用

配置告警

prometheus指定rules目录

编辑 prometheus-configmap.yaml 添加报警信息

1
2
3
# 添加:指定读取rules配置
rules_files:
- /etc/config/rules/*.rules

configmap存储告警规则

创建yaml文件同过configmap存储告警规则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#vim prometheus-rules.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: prometheus-rules
namespace: monitoring
data:
# 通用角色
general.rules: |
groups:
- name: general.rules
rules:
- alert: InstanceDown
expr: up == 0
for: 1m
labels:
severity: error
annotations:
summary: "Instance {{ $labels.instance }} 停止工作"
description: "{{ $labels.instance }} job {{ $labels.job }} 已经停止5分钟以上."
# Node对所有资源的监控
node.rules: |
groups:
- name: node.rules
rules:
- alert: NodeFilesystemUsage
expr: 100 - (node_filesystem_free_bytes{fstype=~"ext4|xfs"} / node_filesystem_size_bytes{fstype=~"ext4|xfs"} * 100) > 80
for: 1m
labels:
severity: warning
annotations:
summary: "Instance {{ $labels.instance }} : {{ $labels.mountpoint }} 分区使用率过高"
description: "{{ $labels.instance }}: {{ $labels.mountpoint }} 分区使用大于80% (当前值: {{ $value }})"

- alert: NodeMemoryUsage
expr: 100 - (node_memory_MemFree_bytes+node_memory_Cached_bytes+node_memory_Buffers_bytes) / node_memory_MemTotal_bytes * 100 > 80
for: 1m
labels:
severity: warning
annotations:
summary: "Instance {{ $labels.instance }} 内存使用率过高"
description: "{{ $labels.instance }}内存使用大于80% (当前值: {{ $value }})"

- alert: NodeCPUUsage
expr: 100 - (avg(irate(node_cpu_seconds_total{mode="idle"}[5m])) by (instance) * 100) > 60
for: 1m
labels:
severity: warning
annotations:
summary: "Instance {{ $labels.instance }} CPU使用率过高"
description: "{{ $labels.instance }}CPU使用大于60% (当前值: {{ $value }})"

configmap挂载到容器rules目录

修改挂载点位置,使用之前部署的prometheus动态PV

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#vim prometheus-statefulset.yaml
volumeMounts:
- name: config-volume
mountPath: /etc/config
- name: prometheus-data
mountPath: /data
# 添加:指定rules的configmap配置文件名称
- name: prometheus-rules
mountPath: /etc/config/rules
subPath: ""
terminationGracePeriodSeconds: 300
volumes:
- name: config-volume
configMap:
name: prometheus-config
# 添加:name rules
- name: prometheus-rules
# 添加:配置文件
configMap:
# 添加:定义文件名称
name: prometheus-rules

alertmananger报警配置说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#cat alertmanager-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
# 配置文件名称
name: alertmanager-config
namespace: kube-system
labels:
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: EnsureExists
data:
alertmanager.yml: |
global:
resolve_timeout: 5m
# 告警自定义邮件
smtp_smarthost: 'smtp.163.com:25'
smtp_from: 'w.jjwx@163.com'
smtp_auth_username: 'w.jjwx@163.com'
smtp_auth_password: '密码'
smtp_hello: '163.com'
smtp_require_tls: false
route:
# 这里的标签列表是接收到报警信息后的重新分组标签,例如,接收到的报警信息里面有许多具有 cluster=A 和 alertname=LatncyHigh 这样的标签的报警信息将会批量被聚合到一个分组里面
group_by: ['job','alertname','severity']
# 当一个新的报警分组被创建后,需要等待至少group_wait时间来初始化通知,这种方式可以确保您能有足够的时间为同一分组来获取多个警报,然后一起触发这个报警信息。
group_wait: 30s
group_interval: 5m
# 当第一个报警发送后,等待'group_interval'时间来发送新的一组报警信息。
repeat_interval: 12h
# 如果一个报警信息已经发送成功了,等待'repeat_interval'时间来重新发送他们

#group_interval: 5m
#repeat_interval: 12h

receiver: default #默认的receiver:如果一个报警没有被一个route匹配,则发送给默认的接收器
routes:
- receiver: webhook
match:
alertname: NodeMemoryUsage #匹配这个内存报警

receivers:
- name: 'default'
email_configs:
- to: '314144952@qq.com'
send_resolved: true
- name: 'webhook'
webhook_configs:
- url: 'http://dingtalk-hook:5000'
send_resolved: true

部分参数说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
route:
# 这里的标签列表是接收到报警信息后的重新分组标签,例如,接收到的报警信息里面有许多具有 cluster=A 和 alertname=LatncyHigh 这样的标签的报警信息将会批量被聚合到一个分组里面
group_by: ['alertname', 'cluster']
# 当一个新的报警分组被创建后,需要等待至少group_wait时间来初始化通知,这种方式可以确保您能有足够的时间为同一分组来获取多个警报,然后一起触发这个报警信息。
group_wait: 30s

# 当第一个报警发送后,等待'group_interval'时间来发送新的一组报警信息。
group_interval: 5m

# 如果一个报警信息已经发送成功了,等待'repeat_interval'时间来重新发送他们
repeat_interval: 5m

# 默认的receiver:如果一个报警没有被一个route匹配,则发送给默认的接收器
receiver: default

# 上面所有的属性都由所有子路由继承,并且可以在每个子路由上进行覆盖。

配置告警信息模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
apiVersion: v1
kind: ConfigMap
metadata:
name: alertmanager-tmpl
namespace: monitoring
data:
wechat.tmpl: |
{{ define "wechat.default.message" }}
{{- if gt (len .Alerts.Firing) 0 -}}{{ range .Alerts }}
@警报
状态: {{ .Status }}
名称: {{ .Labels.alertname }}
级别: {{ .Labels.severity }}
实例: {{ .Labels.instance }}
信息: {{ .Annotations.summary }}
详情: {{ .Annotations.description }}
时间: {{ .StartsAt.Format "2006-01-02 15:04:05" }}
{{ end }}{{ end -}}
{{- if gt (len .Alerts.Resolved) 0 -}}{{ range .Alerts }}
@恢复
状态: {{ .Status }}
名称: {{ .Labels.alertname }}
级别: {{ .Labels.severity }}
实例: {{ .Labels.instance }}
信息: {{ .Annotations.summary }}
详情: {{ .Annotations.description }}
时间: {{ .StartsAt.Format "2006-01-02 15:04:05" }}
恢复: {{ .EndsAt.Format "2006-01-02 15:04:05" }}
{{ end }}{{ end -}}
{{- end }}
email.tmpl: |
{{ define "email.default.html" }}
{{- if gt (len .Alerts.Firing) 0 -}}{{ range .Alerts }}
@警报
状态: {{ .Status }}
名称: {{ .Labels.alertname }}
级别: {{ .Labels.severity }}
实例: {{ .Labels.instance }}
信息: {{ .Annotations.summary }}
详情: {{ .Annotations.description }}
时间: {{ .StartsAt.Format "2006-01-02 15:04:05" }}
{{ end }}{{ end -}}
{{- if gt (len .Alerts.Resolved) 0 -}}{{ range .Alerts }}
@恢复
状态: {{ .Status }}
名称: {{ .Labels.alertname }}
级别: {{ .Labels.severity }}
实例: {{ .Labels.instance }}
信息: {{ .Annotations.summary }}
详情: {{ .Annotations.description }}
时间: {{ .StartsAt.Format "2006-01-02 15:04:05" }}
恢复: {{ .EndsAt.Format "2006-01-02 15:04:05" }}
{{ end }}{{ end -}}
{{ end }}
--------------------本文结束,感谢您的阅读--------------------