Skip to content

1. Alertmanager简介

官当

Alertmanager 主要用于接收 Prometheus 发送的告警信息,它支持丰富的告警通知渠道,例如邮件、微信、钉钉、Slack 等常用沟通工具,而且很容易做到告警信息进行去重,降噪,分组等,是一款很好用的告警通知系统。

1.1 AlertManager 常用的功能

抑制:指的是当某一告警信意发送后,可以停止由此告警引发的其它告警,避免相同的告警信息重复发送8

静默:静默也是一种机制,指的是依据设置的标签,对告警行为进行静默处理。

发送告警:支持配置多种告警规则,可以根据不同的路由配置,采用不同的告警方式发送告警通知。

告警分组:分组机制可以将详细的告警信息合并成一个通知。

1.2 Prometheus 和 AlertManager 的关系

prometheus 触发一条告警的过程:

prometheus--->触发阈值--->超出持续时间--->alertmanager--->分组|抑制|静默--->媒体类型--->邮件|钉钉|微信等

image-20240702155232473

1.3 发送警告生命周期

一条告警产生后,它的状态可能是 inactivepending 或者 firing 中的一种,还要经过 Alertmanager 的分组、抑制处理、静默处理、去重处理和降噪处理最后再发送给接收者。这个过程中可能会因为各种原因会导致告警产生了却最终没有进行通知,可以通过下图了解整个告警的生命周期:

img

报警状态分 3 种:

  • inactive:没有异常.
  • pending:已触发阈值,但未满足告警持续时间(即 rule 中的 for 字段).
  • firing:已触发阈值且满足条件并发送至 alertmanager.

2. AlertManager核心概念

2.1 分组

被触发的警报合并为一个警报进行通知,避免瞬间突发性的接受大量警报通知,使得管理员无法对问题进行快速定位。

  • 场景

在Kubernetes集群中,运行着重量级规模的实例,即便是集群中持续很小一段时间的网络延迟或者延迟导致网络抖动,也会引发大量类似服务应用无法连接DB的故障。如果在警报规则中定义每一个应用实例都发送警报,那么到最后的结果就是会有大量的警报信息通过Alertmanager发送给咱们的运维及研发小伙伴。

2.2 抑制

Inhibition 是当某条警报已经发送,停止重复发送由此警报引发的其他异常或故障的警报机制

2.3 静默

silences提供了一个简单的机制,根据标签快速对警报进行静默处理;对传进来的警报进行匹配检查,如果接受到警报符合静默的配置,Alertmanager则不会发送警报通知。

  • 场景

1.用于解决严重生产故障问题时因所花费的时间过长,通过静默设置避免接收到过多的无用通知;

2.在已知的例行维护中,防止对例行维护中的机器发送不必要的告警;

设置静默

image-20240703145323614

3. Alertmanager部署

3.1 创建存储

yaml
[root@kube-master alertmanager]# cat 1.alertmanager-storage.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: alertmanager-pvc
  namespace: monitor
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: "nfs-provisioner-storage"
  resources:
    requests:
      storage: 5Gi
[root@kube-master alertmanager]# cat 1.alertmanager-storage.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: alertmanager-pvc
  namespace: monitor
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: "nfs-provisioner-storage"
  resources:
    requests:
      storage: 5Gi
  • apply
bash
kubectl apply -f 1.alertmanager-storage.yaml

#查看
[root@kube-master alertmanager]# kubectl get pvc -nmonitor
NAME                  STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS              AGE
alertmanager-pvc      Bound    pvc-07eac89f-672f-4352-a3c7-adb136ec2295   5Gi        RWX            nfs-provisioner-storage   3s
kubectl apply -f 1.alertmanager-storage.yaml

#查看
[root@kube-master alertmanager]# kubectl get pvc -nmonitor
NAME                  STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS              AGE
alertmanager-pvc      Bound    pvc-07eac89f-672f-4352-a3c7-adb136ec2295   5Gi        RWX            nfs-provisioner-storage   3s

3.2 创建configMap

yaml
[root@kube-master alertmanager]# cat 2.alertmanager-configmap-wechat.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: alertmanager-config
  namespace: monitor
data:
  alertmanager.yml: |-
    global:
      resolve_timeout: 1m
      smtp_smarthost: 'smtp.qq.com:465'     # 邮箱服务器的SMTP主机配置
      smtp_from: 'xxxx@xxxx.cn'    # 发送邮件主题
      smtp_auth_username: 'xxxx@xxxx.cn'      # 登录用户名
      smtp_auth_password: 'yfXBjxxxxDwYTjn'    # 此处的auth password是邮箱的第三方登录授权密码,而非用户密码
      smtp_require_tls: false           # 有些邮箱需要开启此配置,这里使用的是企微邮箱,仅做测试,不需要开启此功能。

    templates:
      - '/etc/alertmanager/*.tmpl'
    route:
      group_by: ['env','instance','type','group','job','alertname','cluster']
      group_wait: 10s
      group_interval: 2m
      repeat_interval: 10m
      receiver: 'wechat'
      routes:
      - receiver: 'wechat'
        match:
          severity: critical

      - receiver: 'webhook'
        match:
          severity: critical

    receivers:
    - name: 'email'
      email_configs:
      - to: 'xxxx@163.com'
        send_resolved: true
        html: '{{ template "email.to.html" . }}'

    - name: 'wechat'
      wechat_configs:
      - corp_id: 'wwe158c08abxxxx06'
        to_party: '1'
        to_user: '@all'
        agent_id: 100xxx
        api_secret: '0UATPXAb10hW0Kbzbi69xxxxxxx5BTIapn_rs'
        send_resolved: true

    - name: 'webhook'
      webhook_configs:
      - url: 'http://webhook-dingtalk.monitor.svc.cluster.local:8060/dingtalk/webhook1/send'
        send_resolved: true

    inhibit_rules:
      - source_match:
          severity: 'critical'
        target_match:
          severity: 'warning'
        equal: ['alertname', 'dev', 'instance']

  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 }}

  email.tmpl: |-
    {{ define "email.from" }}xxx.com{{ end }}
    {{ define "email.to" }}xxx.com{{ end }}
    {{ define "email.to.html" }}
    {{- if gt (len .Alerts.Firing) 0 -}}
    {{ range .Alerts }}
    ========= 监控报警 =========<br>
    告警程序: prometheus_alert <br>
    告警级别: {{ .Labels.severity }} <br>
    告警类型: {{ .Labels.alertname }} <br>
    告警主机: {{ .Labels.instance }} <br>
    告警主题: {{ .Annotations.summary }}  <br>
    告警详情: {{ .Annotations.description }} <br>
    触发时间: {{ .StartsAt.Format "2006-01-02 15:04:05" }} <br>
    ========= = end =  =========<br>
    {{ end }}{{ end -}}

    {{- if gt (len .Alerts.Resolved) 0 -}}
    {{ range .Alerts }}
    ========= 告警恢复 =========<br>
    告警程序: prometheus_alert <br>
    告警级别: {{ .Labels.severity }} <br>
    告警类型: {{ .Labels.alertname }} <br>
    告警主机: {{ .Labels.instance }} <br>
    告警主题: {{ .Annotations.summary }} <br>
    告警详情: {{ .Annotations.description }} <br>
    触发时间: {{ .StartsAt.Format "2006-01-02 15:04:05" }} <br>
    恢复时间: {{ .EndsAt.Format "2006-01-02 15:04:05" }} <br>
    ========= = end =  =========<br>
    {{ end }}{{ end -}}

    {{- end }}
[root@kube-master alertmanager]# cat 2.alertmanager-configmap-wechat.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: alertmanager-config
  namespace: monitor
data:
  alertmanager.yml: |-
    global:
      resolve_timeout: 1m
      smtp_smarthost: 'smtp.qq.com:465'     # 邮箱服务器的SMTP主机配置
      smtp_from: 'xxxx@xxxx.cn'    # 发送邮件主题
      smtp_auth_username: 'xxxx@xxxx.cn'      # 登录用户名
      smtp_auth_password: 'yfXBjxxxxDwYTjn'    # 此处的auth password是邮箱的第三方登录授权密码,而非用户密码
      smtp_require_tls: false           # 有些邮箱需要开启此配置,这里使用的是企微邮箱,仅做测试,不需要开启此功能。

    templates:
      - '/etc/alertmanager/*.tmpl'
    route:
      group_by: ['env','instance','type','group','job','alertname','cluster']
      group_wait: 10s
      group_interval: 2m
      repeat_interval: 10m
      receiver: 'wechat'
      routes:
      - receiver: 'wechat'
        match:
          severity: critical

      - receiver: 'webhook'
        match:
          severity: critical

    receivers:
    - name: 'email'
      email_configs:
      - to: 'xxxx@163.com'
        send_resolved: true
        html: '{{ template "email.to.html" . }}'

    - name: 'wechat'
      wechat_configs:
      - corp_id: 'wwe158c08abxxxx06'
        to_party: '1'
        to_user: '@all'
        agent_id: 100xxx
        api_secret: '0UATPXAb10hW0Kbzbi69xxxxxxx5BTIapn_rs'
        send_resolved: true

    - name: 'webhook'
      webhook_configs:
      - url: 'http://webhook-dingtalk.monitor.svc.cluster.local:8060/dingtalk/webhook1/send'
        send_resolved: true

    inhibit_rules:
      - source_match:
          severity: 'critical'
        target_match:
          severity: 'warning'
        equal: ['alertname', 'dev', 'instance']

  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 }}

  email.tmpl: |-
    {{ define "email.from" }}xxx.com{{ end }}
    {{ define "email.to" }}xxx.com{{ end }}
    {{ define "email.to.html" }}
    {{- if gt (len .Alerts.Firing) 0 -}}
    {{ range .Alerts }}
    ========= 监控报警 =========<br>
    告警程序: prometheus_alert <br>
    告警级别: {{ .Labels.severity }} <br>
    告警类型: {{ .Labels.alertname }} <br>
    告警主机: {{ .Labels.instance }} <br>
    告警主题: {{ .Annotations.summary }}  <br>
    告警详情: {{ .Annotations.description }} <br>
    触发时间: {{ .StartsAt.Format "2006-01-02 15:04:05" }} <br>
    ========= = end =  =========<br>
    {{ end }}{{ end -}}

    {{- if gt (len .Alerts.Resolved) 0 -}}
    {{ range .Alerts }}
    ========= 告警恢复 =========<br>
    告警程序: prometheus_alert <br>
    告警级别: {{ .Labels.severity }} <br>
    告警类型: {{ .Labels.alertname }} <br>
    告警主机: {{ .Labels.instance }} <br>
    告警主题: {{ .Annotations.summary }} <br>
    告警详情: {{ .Annotations.description }} <br>
    触发时间: {{ .StartsAt.Format "2006-01-02 15:04:05" }} <br>
    恢复时间: {{ .EndsAt.Format "2006-01-02 15:04:05" }} <br>
    ========= = end =  =========<br>
    {{ end }}{{ end -}}

    {{- end }}
  • apply
bash
kubectl  apply -f 2.alertmanager-configmap-wechat.yaml
kubectl  apply -f 2.alertmanager-configmap-wechat.yaml

3.3 创建dp

yaml
[root@kube-master alertmanager]# cat 3.alertmanager-deploy.yaml
apiVersion: v1
kind: Service
metadata:
  name: alertmanager
  namespace: monitor
  labels:
    k8s-app: alertmanager
spec:
  type: ClusterIP
  ports:
  - name: http
    port: 9093
    targetPort: 9093
  selector:
    k8s-app: alertmanager
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: alertmanager
  namespace: monitor
  labels:
    k8s-app: alertmanager
spec:
  replicas: 1
  selector:
    matchLabels:
      k8s-app: alertmanager
  template:
    metadata:
      labels:
        k8s-app: alertmanager
    spec:
      containers:
      - name: alertmanager
        image: registry.cn-zhangjiakou.aliyuncs.com/hsuing/alertmanager:v0.24.0
        imagePullPolicy: IfNotPresent
        ports:
        - name: http
          containerPort: 9093
        args:
        ## 指定容器中AlertManager配置文件存放地址 (Docker容器中的绝对位置)
        - "--config.file=/etc/alertmanager/alertmanager.yml"
        ## 指定AlertManager管理界面地址,用于在发生的告警信息中,附加AlertManager告警信息页面地址
        - "--web.external-url=https://alertmanager.ikubernetes.net"
        ## 指定监听的地址及端口
        - '--cluster.advertise-address=0.0.0.0:9093'
        ## 指定数据存储位置 (Docker容器中的绝对位置)
        - "--storage.path=/alertmanager"
        resources:
          limits:
            cpu: 1000m
            memory: 512Mi
          requests:
            cpu: 500m
            memory: 512Mi
        readinessProbe:
          httpGet:
            path: /-/ready
            port: 9093
          initialDelaySeconds: 5
          timeoutSeconds: 10
        livenessProbe:
          httpGet:
            path: /-/healthy
            port: 9093
          initialDelaySeconds: 30
          timeoutSeconds: 30
        volumeMounts:
        - name: data
          mountPath: /alertmanager
        - name: config
          mountPath: /etc/alertmanager
      - name: configmap-reload
        #image: jimmidyson/configmap-reload:v0.7.1
        image: registry.cn-zhangjiakou.aliyuncs.com/hsuing/configmap-reload:v0.9.0
        args:
        - "--volume-dir=/etc/config"
        - "--webhook-url=http://localhost:9093/-/reload"
        resources:
          limits:
            cpu: 100m
            memory: 100Mi
          requests:
            cpu: 100m
            memory: 100Mi
        volumeMounts:
        - name: config
          mountPath: /etc/config
          readOnly: true
      volumes:
      - name: data
        persistentVolumeClaim:
          claimName: alertmanager-pvc
      - name: config
        configMap:
          name: alertmanager-config
[root@kube-master alertmanager]# cat 3.alertmanager-deploy.yaml
apiVersion: v1
kind: Service
metadata:
  name: alertmanager
  namespace: monitor
  labels:
    k8s-app: alertmanager
spec:
  type: ClusterIP
  ports:
  - name: http
    port: 9093
    targetPort: 9093
  selector:
    k8s-app: alertmanager
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: alertmanager
  namespace: monitor
  labels:
    k8s-app: alertmanager
spec:
  replicas: 1
  selector:
    matchLabels:
      k8s-app: alertmanager
  template:
    metadata:
      labels:
        k8s-app: alertmanager
    spec:
      containers:
      - name: alertmanager
        image: registry.cn-zhangjiakou.aliyuncs.com/hsuing/alertmanager:v0.24.0
        imagePullPolicy: IfNotPresent
        ports:
        - name: http
          containerPort: 9093
        args:
        ## 指定容器中AlertManager配置文件存放地址 (Docker容器中的绝对位置)
        - "--config.file=/etc/alertmanager/alertmanager.yml"
        ## 指定AlertManager管理界面地址,用于在发生的告警信息中,附加AlertManager告警信息页面地址
        - "--web.external-url=https://alertmanager.ikubernetes.net"
        ## 指定监听的地址及端口
        - '--cluster.advertise-address=0.0.0.0:9093'
        ## 指定数据存储位置 (Docker容器中的绝对位置)
        - "--storage.path=/alertmanager"
        resources:
          limits:
            cpu: 1000m
            memory: 512Mi
          requests:
            cpu: 500m
            memory: 512Mi
        readinessProbe:
          httpGet:
            path: /-/ready
            port: 9093
          initialDelaySeconds: 5
          timeoutSeconds: 10
        livenessProbe:
          httpGet:
            path: /-/healthy
            port: 9093
          initialDelaySeconds: 30
          timeoutSeconds: 30
        volumeMounts:
        - name: data
          mountPath: /alertmanager
        - name: config
          mountPath: /etc/alertmanager
      - name: configmap-reload
        #image: jimmidyson/configmap-reload:v0.7.1
        image: registry.cn-zhangjiakou.aliyuncs.com/hsuing/configmap-reload:v0.9.0
        args:
        - "--volume-dir=/etc/config"
        - "--webhook-url=http://localhost:9093/-/reload"
        resources:
          limits:
            cpu: 100m
            memory: 100Mi
          requests:
            cpu: 100m
            memory: 100Mi
        volumeMounts:
        - name: config
          mountPath: /etc/config
          readOnly: true
      volumes:
      - name: data
        persistentVolumeClaim:
          claimName: alertmanager-pvc
      - name: config
        configMap:
          name: alertmanager-config

3.4 创建ingress

yaml
[root@kube-master alertmanager]# cat 4.alertmanager-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  namespace: monitor
  name: alertmanager-ingress
spec:
  ingressClassName: nginx
  rules:
  - host: alertmanager.ikubernetes.net
    http:
      paths:
        - pathType: Prefix
          backend:
            service:
              name: alertmanager
              port:
                number: 9093
          path: /
[root@kube-master alertmanager]# cat 4.alertmanager-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  namespace: monitor
  name: alertmanager-ingress
spec:
  ingressClassName: nginx
  rules:
  - host: alertmanager.ikubernetes.net
    http:
      paths:
        - pathType: Prefix
          backend:
            service:
              name: alertmanager
              port:
                number: 9093
          path: /
  • 效果

image-20240702223006412

  • 配置文件热更新
curl -XPOST http://alertmanager.ikubernetes.net/-/reload
curl -XPOST http://alertmanager.ikubernetes.net/-/reload

4. Alertmanager高可用

yaml
部署模式:可以使用 StatefulSet 控制器来部署 Alertmanager,因为它可以保证每个 Pod 有唯一的网络标识和持久化存储。

存储:为 Alertmanager 配置持久化存储,例如使用 PersistentVolumes (PV) 和 PersistentVolumeClaims (PVC)。这可以确保即使 Pod 重启或迁移,配置和数据也不会丢失。

服务发现:配置服务发现机制,以便 Prometheus 可以发现并连接到所有 Alertmanager 实例。

配置:在 Alertmanager 的配置文件中,设置 cluster.peer 参数,这样每个实例都可以知道其他实例的位置,并形成集群。

网络:确保 Alertmanager 实例之间可以互相通信,这通常通过集群内部的网络通信实现。

负载均衡:在 Alertmanager 前面设置一个负载均衡器,以便 Prometheus 可以通过单个端点与所有实例通信。

监控:部署监控工具来监控 Alertmanager 集群的健康状况。
部署模式:可以使用 StatefulSet 控制器来部署 Alertmanager,因为它可以保证每个 Pod 有唯一的网络标识和持久化存储。

存储:为 Alertmanager 配置持久化存储,例如使用 PersistentVolumes (PV) 和 PersistentVolumeClaims (PVC)。这可以确保即使 Pod 重启或迁移,配置和数据也不会丢失。

服务发现:配置服务发现机制,以便 Prometheus 可以发现并连接到所有 Alertmanager 实例。

配置:在 Alertmanager 的配置文件中,设置 cluster.peer 参数,这样每个实例都可以知道其他实例的位置,并形成集群。

网络:确保 Alertmanager 实例之间可以互相通信,这通常通过集群内部的网络通信实现。

负载均衡:在 Alertmanager 前面设置一个负载均衡器,以便 Prometheus 可以通过单个端点与所有实例通信。

监控:部署监控工具来监控 Alertmanager 集群的健康状况。