Про alertmanager и slack

    А именно, коротенькая заметка о настройке компактных, но информативных уведомлений с помощью шаблонизатора из Go, используемого alertmanager.

    Целью будут сообщения вида 'Free disk space is less than 15% on example_host ( /mnt/a, /mnt/b )', содержащие тип проблемы, имя хоста и соответствующие параметры, в данном примере - переполненные разделы.

    В устаревшем Zabbix проблем с этим не возникает - просто генерим нужный текст и отдаём его в Slack. Prometheus тоже так умеет, достаточно записать нужный текст в annotations. Но при этом пропадёт то, чего в Zabbix нет в принципе - группировка алертов. То есть количество уведомлений будет равно количеству алертов, а мы хотим на каждый хост будет получать только по одному уведомлению, независимо от количества алертов одного типа.

    Простым рабочим решением будет создание отдельного receiver для каждого типа алертов, но это вопиющее нарушение принципа DRY с соответствующими проблемами.

    Посредством же небольшой правки настройки alert и использования шаблонизатора в конфиге alertmanager мы сможем получить универсальный receiver для выдачи подобных сообщений.

    Всё, что нам надо сделать с alert, это добавить в раздел annotations строку data: "{{ $labels.mountpoint }}", где mountpoint - метка, которую мы хотим увидеть в сообщении. Нужно это для того, чтобы в alertmanager интересующие нас данные всегда лежали в одной переменной независимо от типа алерта. Полная настройка выглядит так:

  - alert: DiskSpaceLow
    expr: '100-node_filesystem_avail_bytes{mountpoint!="/boot", fstype=~"ext3|ext4|xfs"}/node_filesystem_size_bytes*100>85'
    for: 5m
    labels:
      severity: high
    annotations:
      summary: Free disk space is less than 15% on {{ $labels.instance }}
      data: "{{ $labels.mountpoint }}"

    {{ $labels.instance }} можно в summary не указывать, а тоже отображать его с помощью шаблона, но тогда придётся отдельно настраивать алерты, к хостам не привязанные.

    В настройке alertmanager задаём следующие параметры по умолчанию (никто, впрочем, не мешает их задавать для каждого алерта по отдельности):

route:
  group_by: ['alertname', 'instance']
  receiver: 'default'

    И, наконец, receiver:

- name: 'default'
  slack_configs:
  - channel: '#monitoring'
    color: '{{ if eq .Status "firing" }}#ff0000{{ else }}#00ff00{{ end }}'
    username: 'aaa'
    icon_url: 'http://example.com/logo.png'
    send_resolved: true
    title: '{{ .CommonAnnotations.summary }}{{ if (index .Alerts 0).Annotations.data }} ( {{ range $i, $a := .Alerts }}{{if $i}}, {{end}}{{ .Annotations.data }}{{ end }} ){{ end}}'
    text: ''
    title_link: ''

    Итого для алертов с существующей annotation data мы получим сообщение типа показанного ранее, а для прочих будет выведено только annotation summary. Естественно, подобным образом можно организовать отображение информации об алертах, сгруппированных по другим параметрам. К сожалению, по мнению Б.Бразила потребности в группировке алертов по статусу нет, так что при совпадении прочих параметров сообщения разных статусов будут объединяться в одно. В принципе, побороть можно, но об этом как-нибудь в другой раз.