В этом материале я постараюсь описать один из способов организации алертов в микросервисной архитектуре.

В незапамятные времена, когда еще не вышла последняя серия «Во все тяжкие», алерты чаще всего хранились в одном месте — будь то icinga, zabbix, TICK stack или тот же самый Prometheus. В этом есть свои плюсы — можно легко отслеживать изменения, грепнуть нужный алерт, накидать CI и так далее. Но когда речь заходит о микросервисной архитектура, где бизнес логика представлена отдельными сервисами, было бы логичным держать бизнес алертинг в коде микросервиса.

Что ж, давайте попробуем реализовать такой подход.

В представленном примере будет использоваться система мониторинга Prometheus/Alertmanager, развернутая в k8s. Микросервис тоже работает в k8s. Нотификации будем слать в Slack.

Итак приступим.

Чтобы хранить тело алерта рядом с микросервисом, воспользуемся ресурсом, который называется PrometheusRule.

Добавим в values нашего микросервиса нужные значения и создадим правило в директории с хельм чартом:

{{- if .Values.prometheusRule.enabled }}
---
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  labels:
    {{- include "ms-awesome.labels" . | indent 4 }}
    release: {{ .Values.prometheusRule.release |default("kube-prometheus-stack") }}
  name: ms-awesome-rule
spec:
  groups:
    - name: ms-awesome-alerts
      rules:
       - alert: ms-awesome-alert
         expr: test_metric{kubernetes_pod_name=~"ms-awesome.*"} == 1
         for: 20s
         labels:
           severity: critical
           product: "{{ .Values.alert_info.product }}"
         annotations:
           description: 'Test header in ms-awesome alert'
           summary: 'This is test alert from ms-awesome'
{{- end }}

Далее установим и настроим Prometheus и Alertmanager. Для этого воспользуемся чартом kube-prometheus-stack. Настроим отправку алертов на основе label product:

ms-awesome-k8s-chart.yml
---
## Alertmanager configuration directives
## ref: https://prometheus.io/docs/alerting/configuration/#configuration-file
##      https://prometheus.io/webtools/alerting/routing-tree-editor/

alertmanager:
  enabled: true
  ## Api that prometheus will use to communicate with alertmanager. Possible values are v1, v2
  ##
  apiVersion: v2

  alertmanagerSpec:
    externalUrl: http://prometheus-url-for-our-ms/prometheus/alerts?search=

  ## Service account for Alertmanager to use.
  ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
  ##
  serviceAccount:
    create: true
    name: ""
    annotations: {}

  ## Configure pod disruption budgets for Alertmanager
  ## ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb/#specifying-a-poddisruptionbudget
  ## This configuration is immutable once created and will require the PDB to be deleted to be changed
  ## https://github.com/kubernetes/kubernetes/issues/45398
  ##
  podDisruptionBudget:
    enabled: false
    minAvailable: 1
    maxUnavailable: ""

  config:
    global:
      resolve_timeout: 5m
      slack_api_url: 'https://hooks.slack.com/services/awesome-link-for-alerts-channel'
    templates:
      - '/etc/alertmanager/config/*.tmpl'
    route:
      group_by: ['alertname', 'cluster', 'namespace']
      group_wait: 30s
      group_interval: 1m
      repeat_interval: 1m
      receiver: 'blackhole'
      routes:
        - receiver: "default-receiver"
          matchers:
            - severity =~ "critical"
          continue: true
        - receiver: "ms-awesome-receiver"
          matchers:
            - product = "ms-awesome"
            - severity =~ "warning|critical"
          continue: true

    receivers:
      - name: 'blackhole'
      - name: 'default-receiver'
      - name: 'ms-awesome-receiver'
        slack_configs:
          - channel: '{{ index ((index .Alerts 0).Labels) "slack_channel_monitoring" }}'
            color: "{{ if eq .Status `firing` }}#000080{{ else }}good{{ end }}"
            title: '{{ if eq .Status `firing` }}:scream:{{ else }}:heavy_check_mark:{{ end }} [{{ .Status | toUpper }}] {{ .Annotations.description }}'
            text: '{{ .Annotations.summary }}'
  tplConfig: false

  ## Alertmanager template files to format alerts
  ## By default, templateFiles are placed in /etc/alertmanager/config/ and if
  ## they have a .tmpl file suffix will be loaded. See config.templates above
  ## to change, add other suffixes. If adding other suffixes, be sure to update
  ## config.templates above to include those suffixes.
  ## ref: https://prometheus.io/docs/alerting/notifications/
  ##      https://prometheus.io/docs/alerting/notification_examples/
  ##
  ## templateFiles: {}

prometheus:
  ingress:
    hosts:
	  - prometheus-url-for-our-ms
  prometheusSpec:
    externalUrl: http://prometheus-url-for-our-ms

Заливаем хельм чарт с прометеем:

helm upgrade --install kube-prometheus-stack -f ms-awesome-k8s-chart.yml prometheus-community/kube-prometheus-stack -n monitoring

Заливаем чарт с микросервисом.

Если все хорошо, то в неймспейсе, где залит микросервис, должен появится ресурс PrometheusRules, с описанием, которые указано выше. Именно этот ресурс должен в итоге поднять Prometheus. Идем по урлу Prometheus во вкладку alerts, там должен появится наш алерт. В случае, если этого не случилось, нужно проверить лейблы — а именно label release. Его значение должно совпадать со значением, которое указано в Prometheus в параметре ruleSelector. Если они не совпадают, то Prometheus просто не найдет это правило.

Генерируем ошибку, чтобы метрика поменяла значение, ждем, пока алерт поменяет свое состояние, и, если alertmanager настроен правильно, наслаждаемся полученным результатом

p/s

В интернетах есть статья, как прокидывать канал из тела алерта. Эту опция, если честно, я не тестил, но вариант выглядит рабочим. Поэтому если кто то проверит и напишет результат, будет плюсик в карму ))

Комментарии (1)


  1. DANic
    14.04.2023 16:05

    В этой схеме хорошо себя показывает grafana oncall

    Особенно если уже есть легаси мониторинг с алертингом, например zabbix, а нужно добавить алертинг ещё и для микросервисов и получить их все в одном месте

    Плюсом будет возможность использовать alertmaneger grafana, с удобным UI