Prometheus: роутинг алертов в Alertmanager

Автор: | 30/10/2018
 

Есть три рабочих окружения – Dev, Stage, Production.

Есть пачка алертов с разными уровнями важности – info, warning и critical, например:

...
- name: SSLexpiry.rules

  rules:

  - alert: SSLCertExpiring30days
    expr: probe_ssl_earliest_cert_expiry{job="blackbox"} - time() < 86400 * 30
    for: 10m
    labels:
      severity: info
    annotations:
      summary: "SSL certificate warning"
      description: "SSL certificate for the {{ $labels.instance }} will expire within 30 days!"
...

Алерты отправляются в Slack и в OpsGenie.

Задача: в зависимости от окружения и уровня важности – слать либо в только в Slack, либо в Slack + OpsGenie.

OpsGenie, в свою очередь, в зависимости от уровня важности:

  • для warning – оптравляет либо только письмо на почту + сообщение в приложение на телефоне
  • для алертов уровня critical – письмо на почту + сообщение в приложение + звонок на телефон от бота

Т.е. выглядит всё это так:

  • Dev
    • любые сообщения, независимо от уровня важности – шлём только в Slack
  • Staging:
    • info – только в Slack
    • warning и critical – в Slack и OpsGenie, но для OpsGenie ставим уровень warning (P3)
  • Production
    • info – только в Slack
    • warning и critical – в Slack и OpsGenie, но для OpsGenie ставим уровень critical (P1)

Для разбивки сообщений между Slack и OpsGenie используется три ресивера, при этом в warning и critical ресиверах – для OpsGenie устанавливаются уровни P3 и P1 соответсвенно:

...
receivers:

  - name: 'default'
    slack_configs:
      - send_resolved: true
        title_link: 'https://monitor.example.com/prometheus/alerts'
        title: '{{ if eq .Status "firing" }}:confused:{{ else }}:dancing_panda:{{ end }} [{{ .Status | toUpper }}] {{ .CommonAnnotations.summary }}'
        text: "{{ range .Alerts }}*Priority*: `{{ .Labels.severity | toUpper }}`\nMonitoring host: {{ .Labels.monitor }}\n{{ .Annotations.description }}\n{{ end }}"

  - name: 'warning'
    slack_configs:
      - send_resolved: true
        title_link: 'https://monitor.example.com/prometheus/alerts'
        title: '{{ if eq .Status "firing" }}:disappointed_relieved:{{ else }}:dancing_panda:{{ end }} [{{ .Status | toUpper }}] {{ .CommonAnnotations.summary }}'
        text: "{{ range .Alerts }}*Priority*: `{{ .Labels.severity | toUpper }}`\nMonitoring host: {{ .Labels.monitor }}\n{{ .Annotations.description }}\n{{ end }}"
    opsgenie_configs:
      - priority: P3

  - name: 'critical'
    slack_configs:
      - send_resolved: true
        title_link: 'https://monitor.example.com/prometheus/alerts'
        title: '{{ if eq .Status "firing" }}:scream:{{ else }}:dancing_panda:{{ end }} [{{ .Status | toUpper }}] {{ .CommonAnnotations.summary }}'
        text: "{{ range .Alerts }}*Priority*: `{{ .Labels.severity | toUpper }}`\nMonitoring host: {{ .Labels.monitor }}\n{{ .Annotations.description }}\n{{ end }}"
    opsgenie_configs:
      - priority: P1

И собственно “маршрутизация” алертов выполняется в блоке route:

...
route:

  group_by: ['alertname', 'cluster', 'job', 'env']
  repeat_interval: 24h
  group_interval: 5m

  # capture All Dev + All INFO
  receiver: 'default'

  routes:

    # capture All WARN to the 'warning' with P3
    - match:
        severity: warning
      receiver: warning

      routes:
      # forward Dev WARN to the 'default'
      - match_re:
          env: .*(-dev).*
        receiver: default

    # capture All CRIT to the 'critical' with P1
    - match:
        severity: critical
      receiver: critical

      routes:
      # forward Stage CRIT to the 'warning'
      - match_re:
          env: .*(-stage).*
        receiver: warning
      # forward Dev CRIT to the 'default'
      - match_re:
          env: .*(-dev).*
        receiver: default
...

Тут задаём дефолтный роут ‘default‘ – все алерты, не попавшие под действия правил ниже – будут отправлены через него в ресивер default, который выполняет отправку только в Slack.

Далее, описываем дополнительные маршруты:

  1. в match ловим алерты по тегу severity: warning
  2. во вложенном роуте с помощью match_re проверяем значение тега env – если в нём содержится “-dev” – то отправляем сообщение в ресивер default
  3. все остальные алерты с уровнем warning “возвращаются выше” – и отправляются в receiver: warning

Аналогично поступаем на следующем уровне – ловим алерты с severity: critical, и проверяем их:

  1. если env: .*(-stage).* – шлём в warning
  2. если env: .*(-dev).* – в default
  3. все остальные (остаёся env == production и severity == critical) – отправляем в ресивер critical

Таким же образом можно писать любые условия по тегам, и использовать любое количество вложенных проверок для выбора дальнейшего маршрута алерта.