Установка и настройка Pushgateway для Prometheus

По умолчанию, метрики в Prometheus попадают методом pull — система обращается к агентам (exporter) и забирает данные. Это рекомендованный способ, но мы можем настроить получение метрик методом push с помощью Pushgateway. Схема работы следующая: метрика отправляется скриптом на сервер Pushgateway, а Prometheus забирает данные уже с него.




Установка Pushgateway




Сервис может быть запущен в качестве контейнера docker. Однако, мы рассмотрим вариант со скачиванием бинарника и созданием юнита для его автозапуска.




Переходим на официальную страницу загрузки Pushgateway. Копируем ссылку для скачивания бинарника под Linux:





Используем скопированную ссылку, чтобы загрузить бинарник:




wget https://github.com/prometheus/pushgateway/releases/download/v1.3.1/pushgateway-1.3.1.linux-amd64.tar.gz




Распаковываем архив:




tar zxvf pushgateway-*.tar.gz




Копируем бинарник в каталог /usr/local/bin:




cp pushgateway-*/pushgateway /usr/local/bin/




Создаем пользователя pushgateway:




useradd —no-create-home —shell /bin/false pushgateway




Задаем владельца для нашего бинарника:




chown pushgateway:pushgateway /usr/local/bin/pushgateway




Для возможности запуска Pushgateway в качестве сервиса, создаем юнит-файл:




vi /etc/systemd/system/pushgateway.service




[Unit]

Description=Pushgateway Service

After=network.target



[Service]

User=pushgateway

Group=pushgateway

Type=simple

ExecStart=/usr/local/bin/pushgateway 

    --web.listen-address=":9091" 

    --web.telemetry-path="/metrics" 

    --persistence.file="/tmp/metric.store" 

    --persistence.interval=5m 

    --log.level="info" 

    --log.format="json"

ExecReload=/bin/kill -HUP $MAINPID

Restart=on-failure



[Install]

WantedBy=multi-user.target




* в данном примете мы запустим pushgateway на порту 9091. Также мы указали уровень и формат логов — сами логи можно будет увидеть в файлах /var/log/syslog (Ubuntu) или /var/log/messages (CentOS).




Перечитываем конфигурацию systemd:




systemctl daemon-reload




Разрешаем автозапуск сервиса и стартуем его:




systemctl enable pushgateway —now




Проверяем состояние:




systemctl status pushgateway




Открываем браузер и вводим адрес http://<IP-адрес сервера pushgateway>:9091 — мы должны увидеть меню портала:





Pushgateway готов к работе. Переходим к настройке Prometheus.




Настройка Prometheus




Необходимо добавить задание в Prometheus для подключения к серверу Pushgateway и получения с него метрик. Это делается по такому же принципу, что и получение метрик с экспортеров.




Открываем конфигурационный файл:




vi /etc/prometheus/prometheus.yml




В секцию scrape_configs добавим задание:




...

scrape_configs:

  ...

  - job_name: 'pushgateway'

    honor_labels: true

    static_configs:

      - targets: ['localhost:9091']




* в данном задании мы говорим серверу Prometheus забирать метрики с сервера localhost (локальный сервер) на порту 9091.




Для применения настроек перезапускаем сервис прометея:




systemctl restart prometheus




Проверяем, что сервис работает корректно:




systemctl status prometheus




Можно попробовать отправить метрики в Pushgateway.




Отправка метрик методом push в Pushgateway




Отправку данных можно выполнить http-запросом из bash, например, с помощью пакета curl. Синтаксис следующий:




echo «<Название для метрики> <Значение метрики>» | curl —data-binary @- http://<IP-адрес сервера pushgateway>:9091/metrics/job/<Тег для job>/instance/<Тег для instance>




Например:




echo «Temperature +15» | curl —data-binary @- http://localhost:9091/metrics/job/temperature_metrics/instance/localhost




* в данном примере мы передадим на локальный сервер pushgateway (localhost:9091) метрику Temperature со значением +15.




Теперь мы можем перейти в браузере по адресу http://<IP-адрес сервера pushgateway>:9091/metrics и увидеть отправленную ранее метрику:





Для удаления метрики можно использовать также curl с типом запроса delete, например:




curl -X DELETE http://localhost:9091/metrics/job/temperature_metrics/instance/localhost




Также, удалить группу метрик можно в веб-интерфейсе Pushgateway.




Скрипт на Python




В качестве примера, рассмотрим скрипт, написанный на Python. Для начала, необходимо установить модуль prometheus_client:




pip3 install prometheus_client




Сам скрипт будет выглядеть таким образом:




#!/usr/bin/env python3

# -*- encoding: utf-8 -*-



from prometheus_client import CollectorRegistry, Gauge, push_to_gateway



registry = CollectorRegistry()

g = Gauge('temperature_metrics', 'Description metric', registry=registry)

g.set(22)

push_to_gateway('localhost:9091', job='temperature_lobby', registry=registry)




в данном примере мы отправим в Prometheus через Pushgateway метрику temperature_metrics со значением 22 и job-тегом temperature_lobby.




Источник: https://sidmid.ru/установка-и-настройка-pushgateway-для-prometheus/



2023-01-02T05:42:02
DevOps

Kubernetes — Автоскейлинг приложений при помощи Prometheus и KEDA

Kubernetes позволяет автоматически масштабировать приложения (то есть Pod в развертывании или ReplicaSet) декларативным образом с использованием спецификации Horizontal Pod Autoscaler.




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




Вместо горизонтального автомасштабирования подов, применяется Kubernetes Event Driven Autoscaling (KEDA) — оператор Kubernetes с открытым исходным кодом. Он изначально интегрируется с Horizontal Pod Autoscaler, чтобы обеспечить плавное автомасштабирование (в том числе до/от нуля) для управляемых событиями рабочих нагрузок. Код доступен на GitHub.




Краткий обзор работы системы





На схеме — краткое описание того, как все работает:




  1. Приложение предоставляет метрики количества обращений к HTTP в формате Prometheus.



  2. Prometheus настроен на сбор этих показателей.



  3. Скейлер Prometheus в KEDA настроен на автоматическое масштабирование приложения на основе количества обращений к HTTP.




Теперь подробно расскажу о каждом элементе.




KEDA и Prometheus




Prometheus — набор инструментов для мониторинга и оповещения систем с открытым исходным кодом, часть Cloud Native Computing Foundation. Собирает метрики из разных источников и сохраняет в виде данных временных рядов. Для визуализации данных можно использовать Grafana или другие инструменты визуализации, работающие с API Kubernetes.




KEDA поддерживает концепцию скейлера — он действует как мост между KEDA и внешней системой. Реализация скейлера специфична для каждой целевой системы и извлекает из нее данные. Затем KEDA использует их для управления автоматическим масштабированием.




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




KEDA Prometheus ScaledObject




Скейлер действует как мост между KEDA и внешней системой, из которой нужно получать метрики. ScaledObject — настраиваемый ресурс, его необходимо развернуть для синхронизации развертывания с источником событий, в данном случае с Prometheus.




ScaledObject содержит информацию о масштабировании развертывания, метаданные об источнике события (например, секреты для подключения, имя очереди), интервал опроса, период восстановления и другие данные. Он приводит к соответствующему ресурсу автомасштабирования (определение HPA) для масштабирования развертывания.




Когда объект ScaledObject удаляется, соответствующее ему определение HPA очищается.




Вот определение ScaledObject для нашего примера, в нем используется скейлер Prometheus:




apiVersion: keda.k8s.io/v1alpha1

kind: ScaledObject

metadata:

 name: prometheus-scaledobject

 namespace: default

 labels:

  deploymentName: go-prom-app

spec:

 scaleTargetRef:

   deploymentName: go-prom-app

 pollingInterval: 15

 cooldownPeriod:  30

 minReplicaCount: 1

 maxReplicaCount: 10

 triggers:

 - type: prometheus

  metadata:

    serverAddress:

http://prometheus-service.default.svc.cluster.local:9090

    metricName: access_frequency

    threshold: '3'

    query: sum(rate(http_requests[2m]))




Учтите следующие моменты:




  1. Он указывает на Deployment с именем go-prom-app.



  2. Тип триггера — Prometheus. Адрес сервера Prometheus упоминается вместе с именем метрики, пороговым значением и запросом PromQL, который будет использоваться. Запрос PromQL — sum(rate(http_requests[2m])).



  3. Согласно pollingInterval, KEDA запрашивает цель у Prometheus каждые пятнадцать секунд. Поддерживается минимум один под (minReplicaCount), а максимальное количество подов не превышает maxReplicaCount (в данном примере — десять).




Можно установить minReplicaCount равным нулю. В этом случае KEDA активирует развертывание с нуля до единицы, а затем предоставляет HPA для дальнейшего автоматического масштабирования. Возможен и обратный порядок, то есть масштабирование от единицы до нуля. В примере мы не выбрали ноль, поскольку это HTTP-сервис, а не система по запросу.




Магия внутри автомасштабирования




Пороговое значение используют в качестве триггера для масштабирования развертывания. В нашем примере запрос PromQL sum(rate (http_requests [2m])) возвращает агрегированное значение скорости HTTP-запросов (количество запросов в секунду), ее измеряют за последние две минуты.




Поскольку пороговое значение равно трем, значит, будет один под, пока значение sum(rate (http_requests [2m])) меньше трех. Если же значение возрастает, добавляется дополнительный под каждый раз, когда sum(rate (http_requests [2m])) увеличивается на три. Например, если значение от 12 до 14, то количество подов — четыре.




Теперь давайте попробуем настроить!




Установка KEDA




Вы можете развернуть KEDA несколькими способами, они перечислены в документации. Я использую монолитный YAML:




[root@kub-master-1 ~]# wget https://github.com/kedacore/keda/releases/download/v2.1.0/keda-2.1.0.yaml
[root@kub-master-1 ~]# kubectl apply -f keda-2.1.0.yaml




ну или можно установить через helm




helm repo add kedacore https://kedacore.github.io/charts
helm repo update
kubectl create namespace keda
helm install keda kedacore/keda —namespace keda




я ставил через монолитный файл.
проверим что всё поднялось:




[root@kub-master-1 ~]# kubectl get all -n keda

NAME                                          READY   STATUS    RESTARTS   AGE

pod/keda-metrics-apiserver-57cbdb849f-w7rfg   1/1     Running   0          70m

pod/keda-operator-58cb545446-5rblj            1/1     Running   0          70m



NAME                             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE

service/keda-metrics-apiserver   ClusterIP   10.100.134.31   <none>        443/TCP,80/TCP   70m



NAME                                     READY   UP-TO-DATE   AVAILABLE   AGE

deployment.apps/keda-metrics-apiserver   1/1     1            1           70m

deployment.apps/keda-operator            1/1     1            1           70m



NAME                                                DESIRED   CURRENT   READY   AGE

replicaset.apps/keda-metrics-apiserver-57cbdb849f   1         1         1       70m

replicaset.apps/keda-operator-58cb545446            1         1         1       70m





3. Пример работы




создаём namespace




kubectl create ns my-site




запускаем обычное приложение например apache:




[root@kub-master-1 ~]# cat my-site.yaml




---

apiVersion: apps/v1

kind: Deployment

metadata:

  name: my-deployment-apache

  namespace: my-site

spec:

  replicas: 1

  selector:

    matchLabels:

      app: apache # по вот этому лейблу репликасет цепляет под

# тут описывается каким мокаром следует обновлять поды

  strategy:

    rollingUpdate:

      maxSurge: 1  # указывает на какое количество реплик можно увеличить

      maxUnavailable: 1 # указывает на какое количество реплик можно уменьшить

#т.е. в одно время при обновлении, будет увеличено на один (новый под) и уменьшено на один (старый под)

    type: RollingUpdate

## тут начинается описание контейнера

  template:

    metadata:

      labels:

        app: apache  # по вот этому лейблу репликасет цепляет под

    spec:

      containers:

        - image: httpd:2.4.43

          name: apache

          ports:

            - containerPort: 80

# тут начинаются проверки по доступности

          readinessProbe: # проверка готово ли приложение

            failureThreshold: 3 #указывает количество провалов при проверке

            httpGet:  # по сути дёргает курлом на 80 порт

              path: /

              port: 80

            periodSeconds: 10 #как часто должна проходить проверка (в секундах)

            successThreshold: 1 #сбрасывает счётчик неудач, т.е. при 3х проверках если 1 раз успешно прошло, то счётчик сбрасывается и всё ок

            timeoutSeconds: 1 #таймаут на выполнение пробы 1 секунда

          livenessProbe: #проверка на жизнь приложения, живо ли оно

            failureThreshold: 3

            httpGet:

              path: /

              port: 80

            periodSeconds: 10

            successThreshold: 1

            timeoutSeconds: 1

            initialDelaySeconds: 10 #означает что первую проверку надо сделать только после 10 секунд



# тут начинается описание лимитов для пода

          resources:

            requests: #количество ресурсов которые резервируются для pod на ноде

              cpu: 60m

              memory: 200Mi

            limits: #количество ресурсов которые pod может использовать(верхняя граница)

              cpu: 120m

              memory: 300Mi




[root@kub-master-1 ~]# cat my-site-service.yaml




---

apiVersion: v1

kind: Service

metadata:

  name: my-service-apache # имя сервиса

  namespace: my-site

spec:

  ports:

  - port: 80  # принимать на 80

    targetPort: 80 # отправлять на 80

  selector:

    app: apache  #отправлять на все поды с данным лейблом

  type: ClusterIP




[root@kub-master-1 ~]# cat my-site-ingress.yaml




---

apiVersion: extensions/v1beta1

kind: Ingress

metadata:

  name: my-ingress

  namespace: my-site

spec:

  rules:

  - host: test.ru  #тут указывается наш домен

    http:

      paths:  #список путей которые хотим обслуживать(он дефолтный и все запросы будут отпаврляться на бэкенд, т.е. на сервис my-service-apache)

      - backend:

          serviceName: my-service-apache  #тут указывается наш сервис 

          servicePort: 80 #порт на котором сервис слушает

#        path: /  все запросы на корень '/' будут уходить на наш сервис





применяем:




[root@kub-master-1 ~]# kubectl apply -f my-site.yaml -f my-site-service.yaml -f my-site-ingress.yaml




проверяем:




[root@kub-worker-1 ~]# curl test.ru
<html><body><h1>It works!</h1></body></html>




[root@kub-master-1 ~]# kubectl get all -n my-site




NAME                                        READY   STATUS    RESTARTS   AGE

pod/my-deployment-apache-859486bd8c-k6bql   1/1     Running   0          20m



NAME                        TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE

service/my-service-apache   ClusterIP   10.100.255.190   <none>        80/TCP    20m



NAME                                   READY   UP-TO-DATE   AVAILABLE   AGE

deployment.apps/my-deployment-apache   1/1     1            1           20m



NAME                                              DESIRED   CURRENT   READY   AGE

replicaset.apps/my-deployment-apache-859486bd8c   1         1         1       20m





будем автоскейлить — для примера по метрике nginx nginx_ingress_controller_requests




запрос в prometheus будет следующий:




sum(irate( nginx_ingress_controller_requests{namespace=»my-site»}[3m] )) by (ingress)*10




т.е. считаем общее количество запросов в неймспейс my-site за 3 минуты




создаём keda сущность:




[root@kub-master-1 ~]# cat hpa-keda.yaml




apiVersion: keda.sh/v1alpha1

kind: ScaledObject

metadata:

  name: prometheus-scaledobject

  namespace: my-site

spec:

  scaleTargetRef:

    name: my-deployment-apache

  minReplicaCount: 1   # Optional. Default: 0

  maxReplicaCount: 8 # Optional. Default: 100

  triggers:

  - type: prometheus

    metadata:

      serverAddress: http://prometheus-kube-prometheus-prometheus.monitoring.svc.cluster.local:9090

      metricName: nginx_ingress_controller_requests

      threshold: '100'

      query: sum(irate(nginx_ingress_controller_requests{namespace="my-site"}[3m])) by (ingress)*10




тут мы указываем в каком namespace нам запускаться:
namespace: my-site




указываем цель, т.е. наш deployment:
name: my-deployment-apache




задаём минимальное и максимальное количество реплик
minReplicaCount: 1 # значение по умолчанию: 0
maxReplicaCount: 8 # значение по умолчанию: 100




есть ещё 2 стандартные переменные отвечающие за то когда поды будут подыматься и убиваться:
pollingInterval: 30 # Optional. Default: 30 seconds
cooldownPeriod: 300 # Optional. Default: 300 seconds




указываем адрес нашего prometheus




serverAddress: http://prometheus-kube-prometheus-prometheus.monitoring.svc.cluster.local:9090
адрес идёт в виде сервис.неймспейс.svc.имя_кластера




указываем нашу метрику:
metricName: nginx_ingress_controller_requests




указываем пороговое значение при котором начнётся автоскейлинг:
threshold: ‘100’




и соответственно наш запрос в prometheus:
query:




всё можно применять:




[root@kub-master-1 ~]# kubectl apply -f hpa-keda.yaml




проверяем:




[root@kub-master-1 ~]# kubectl get horizontalpodautoscalers.autoscaling -n my-site

NAME                               REFERENCE                         TARGETS       MINPODS   MAXPODS   REPLICAS   AGE

keda-hpa-prometheus-scaledobject   Deployment/my-deployment-apache   0/100 (avg)   1         8         1          68m





[root@kub-master-1 ~]# kubectl get pod -n my-site

NAME                                    READY   STATUS    RESTARTS   AGE

my-deployment-apache-859486bd8c-v59b8   1/1     Running   0          37m





а теперь накрутим запросов:




[root@kub-worker-1 ~]# for i in {1..5000}; do curl test.ru; done




проверяем:




[root@kub-master-1 ~]# kubectl get horizontalpodautoscalers.autoscaling -n my-site

NAME                               REFERENCE                         TARGETS            MINPODS   MAXPODS   REPLICAS   AGE

keda-hpa-prometheus-scaledobject   Deployment/my-deployment-apache   34858m/100 (avg)   1         8         7          71m





как видим количество запросов превысило наш лимит и стали создаваться новые поды:




[root@kub-master-1 ~]# kubectl get pod -n my-site

NAME                                    READY   STATUS    RESTARTS   AGE

my-deployment-apache-859486bd8c-6885f   1/1     Running   0          49s

my-deployment-apache-859486bd8c-6mcq4   1/1     Running   0          64s

my-deployment-apache-859486bd8c-cdb6z   1/1     Running   0          64s

my-deployment-apache-859486bd8c-kpwb8   1/1     Running   0          64s

my-deployment-apache-859486bd8c-rmw8d   1/1     Running   0          49s

my-deployment-apache-859486bd8c-v59b8   1/1     Running   0          39m

my-deployment-apache-859486bd8c-xmv28   1/1     Running   0          49s





прекращаем запросы и спустя 5 минут, указанное в переменной cooldownPeriod ненужные поды будут убиты:




[root@kub-master-1 ~]# kubectl get pod -n my-site

NAME                                    READY   STATUS        RESTARTS   AGE

my-deployment-apache-859486bd8c-6885f   0/1     Terminating   0          6m35s

my-deployment-apache-859486bd8c-6mcq4   1/1     Running       0          6m50s

my-deployment-apache-859486bd8c-cdb6z   0/1     Terminating   0          6m50s

my-deployment-apache-859486bd8c-kpwb8   0/1     Terminating   0          6m50s

my-deployment-apache-859486bd8c-rmw8d   0/1     Terminating   0          6m35s

my-deployment-apache-859486bd8c-v59b8   0/1     Terminating   0          44m

my-deployment-apache-859486bd8c-xmv28   0/1     Terminating   0          6m35s



[root@kub-master-1 ~]# kubectl get pod -n my-site

NAME                                    READY   STATUS    RESTARTS   AGE

my-deployment-apache-859486bd8c-6mcq4   1/1     Running   0          7m48s





Источник: https://sidmid.ru/kubernetes-автоскейлинг-приложений-при-помощ/



НАСТРОЙКА ALERTMANAGER PROMETHEUS

Системы мониторинга наподобие Prometheus устанавливаются не только для того чтобы иметь красивые графики состояния сервера в определённый момент, но чтобы вовремя узнавать о возможных проблемах. Для этого у таких систем существуют уведомления — алерты. Prometheus тоже умеет генерировать алерты на основе настраиваемых правил, однако если состояние сервера совпадает с правилом Prometheus будет генерировать алерт при каждом обновлении.




Это не очень удобное поведение, потому что если проблема будет сохранятся долго, вся почта будет заспамлена однообразными сообщениями. Поэтому существует Alertmanager. Это программа из того же пакета что и Prometheus, она позволяет сортировать алерты и отправлять сообщения только первый раз




НАСТРОЙКА ALERTMANAGER ДЛЯ PROMETHEUS




1. НАСТРОЙКА ПРАВИЛ PROMETHEUS




Первым делом необходимо настроить правила Prometheus чтобы программа генерировала алерты при возникновении тех или иных событий. Для правил надо создать отдельный файл в папке с конфигурацией prometheus, например, rules.yaml:




sudo vi /etc/prometheus/rules.yaml




groups:

  - name: имя_группы

    rules:




Файл должен содержать данные в формате yaml. Все правила разбиты на группы. У каждой группы есть имя (name) и список правил (rules). Сначала посмотрим на общий синтаксис правила:




- alert: название_правила

    expr: выражение_при_истинности_которого_отправится_алерт

    for: алерт_будет_отправлен_если_выражение_держится_указанное_время

    labels:

      severity: уровень_важности

    annotations:

      summary: заголовок_алерта

      description: "Подробное описание алерта {{ $переменная }}"




рассмотрим простое правило, отправлять алерт, если хост недоступен:




- alert: PrometheusTargetMissing

    expr: up == 0

    for: 0m

    labels:

      severity: critical

    annotations:

      summary: "Сервис node_exporter на сервере {{ $labels.instance }} недоступен"

      description: "Возможно сервис node_exporter упал или сервер недоступенn VALUE = {{ $value }}n LABELS = {{ $labels }}"




Думаю здесь всё понятно, правило называется PrometheusTargetMissing, дальше идёт условие up == 0. Здесь up это внутренняя метрика prometheus, но здесь можно использовать и метрики предоставляемые экспортёрами. Дальше в параметре for задается время, на протяжении которого проблема должна сохранятся для того чтобы отправить уведомление. Затем идёт описание алерта. В описании можно использовать переменные. Вот они:




  • {{$value}} — содержит значение переменной, участвующей в выражении;



  • {{$labels.instance}} — IP адрес и порт экспортёра, с которым возникла проблема;



  • {{$labels.job}} — имя задачи из конфигурационного файла prometheus;




В конфигурационном файле это правило будет выглядеть вот так:





Этого правила хватит для тестирования alertmanager в этой статье. Больше полезных правил вы можете найти здесь. Теперь осталось добавить созданный файл с правилами в основной файл конфигурации prometheus. Для этого добавьте в него такие строчки:




sudo vi /etc/prometheus/prometheus.yml




rule_files:

  - rules.yml





атем нужно проверить созданные правила, для этого выполните команду:




promtool check rules /etc/prometheus/rules.yml





Если всё прошло успешно, команда выведет слово SUCCESS и количество найденных правил. Если возникла ошибка, убедитесь что у вас верно расставлены отступы, формат YAML очень к нем чувствителен. Все элементы одной группы должны быть на одном уроне.




После внесения всех изменений перезапустите Prometheus:




sudo systemctl restart prometheus




2. УСТАНОВКА ALERTMANAGER




Установить Alertmanager можно из официальных репозториев, но так вы получите программу более старой версии и без веб-интерфейса. Для установки выполните команду:




yum install prometheus-alertmanager




После завершения установки веб-интерфейс можно развернуть командой:




/usr/share/prometheus/alertmanager/generate-ui.sh




Или же можно установить программу из официального сайта. Как и другие программы из этой экосистемы, alertmanager написан на Golang, поэтому состоит из одного исполняемого файла и нескольких конфигурационных файлов. Он не зависит от установленных в системе библиотек.




Сначала скачайте архив с исполняемыми файлами alertmanager из официальной страницы github, например:




wget https://github.com/prometheus/alertmanager/releases/download/v0.21.0/alertmanager-0.21.0.linux-amd64.tar.gz




Дальше распакуйте полученный архив:




tar -xvf alertmanager-0.21.0.linux-amd64.tar.gz




И скопируйте файлы alertmanager и amtool в папку /usr/local/bin:




sudo cp alertmanager-0.21.0.linux-amd64/alertmanager /usr/local/bin/
sudo cp alertmanager-0.21.0.linux-amd64/amtool /usr/local/bin/




Далее надо скопировать конфигурационный файл alertmanager.yml в /etc/prometheus:




sudo cp alertmanager-0.21.0.linux-amd64/alertmanager.yml /etc/prometheus




Дайте пользователю prometheus права на конфигурационный файл:




sudo chown -R prometheus:prometheus /etc/prometheus/alertmanager.yml




Осталось создать systemd сервис, с помощью которого вы сможете запускать программу.




sudo systemctl edit --full --force prometheus-alertmanager




[Unit]

Description=Alertmanager Service

After=network.target

[Service]

EnvironmentFile=-/etc/default/alertmanager

User=prometheus

Group=prometheus

Type=simple

ExecStart=/usr/local/bin/alertmanager $ARGS

ExecReload=/bin/kill -HUP $MAINPID

Restart=on-failure

[Install]

WantedBy=multi-user.target




Теперь можете запустить сервис:




sudo systemctl start prometheus-alertmanager




Веб-интерфейс будет доступен на порту 9093:





3. НАСТРОЙКА PROMETHEUS




Дальше необходимо убедится, что в конфигурационном файле prometheus прописана отправка алертов в alertmanager. Найдите в нём или добавьте такую секцию:




sudo vi /etc/prometheus/alertmanager.yml




alerting:

  alertmanagers:

  - static_configs:

    - targets: ['localhost:9093']




Если были внесены изменения, то prometheus надо перезапустить:




sudo systemctl restart prometheus




4. НАСТРОЙКА ALERTMANAGER




Почти всё готово, теперь надо настроить сам Alertmanager. Надо указать как группировать алерты, когда и куда отправлять уведомления. Вот основное содержание конфигурационного файла:




global:

route:

  group_by: ['по каким параметрам группировать правила']

  group_wait: время_ожидания_перед_отправкой_уведомления_для_группы

  group_interval: время_отправки_повторного_сообщения_для_группы

  repeat_interval: время_до_отправки_повторного_сообщения

  receiver: 'имя_способа_отправки_сообщений'

receivers:

  - name: 'имя_способа_отправки_сообщений'

    конфигурация




Все алерты, поступившие в AlertManager необходимо группировать чтобы не отправлять информацию об одних и тех же событиях несколько раз. Директива group_by указывает какие поля использовать во время группировки. После того, как была создана новая группа алертов, к делу подключается параметр group_wait. Он указывает сколько надо ждать перед отправкой первого сообщения. Параметр отвечает за то, чтобы вы могли получить одним сообщением всю пачку алертов группы, а не отдельное сообщение для каждого алерта.




Параметр group_interval указывает сколько надо ждать после отправки первого сообщения для группы, до отправки повторных сообщений из этой же группы. Но не только он влияет на интервал между сообщениями, ещё есть параметр repeat_interval — который указывает через сколько времени можно повторить отправку уже отправленного алерта.




Вот рабочий пример конфигурации с отправкой уведомлений на email:




sudo vi /etc/prometheus/alertmanager.yml




global:

route:

  group_by: ['alertname']

  group_wait: 30s

  group_interval: 10m

  repeat_interval: 60m

  receiver: 'email'

receivers:

- name: 'email'

  email_configs:

  - to: 'адрес_электронной_почты_получателя'

    from: 'адрес_электронной_почты_отправителя'

    smarthost: 'SMTP_хост:порт'

    auth_username: 'имя_пользователя'

    auth_identity: 'имя_пользователя'

    auth_password: 'пароль'




Все алерты группируются по имени, а значит если для двух разных сереров придут алерты с одинаковым именем, они будут помещены в одну группу. Группа собирается на протяжении 30 секунд, и отправлять повторные сообщения можно не чаще чем раз в час. Дальше идёт настройка отправки сообщений на электронную почту. Для этого используется протокол SMTP. Необходимо указать хост SMTP сервера, имя пользователя и пароль. Вы можете использовать свой SMTP сервер, настроенный на Postfix или Exim или же воспользоваться сторонним сервисом.




Дальше нужно только перезапустить Alertmanager:




sudo systemctl restart prometheus-alertmanager




5. ТЕСТИРОВАНИЕ




Для тестирования на одном из серверов, с которых собирает данные Prometheus можно отключить node_exporter. Для этого выполните:




sudo systemctl stop prometheus-node-exporter




Подождите пока Prometheus снова опросит цели и в AlertManager появится этот алерт:





Сразу же он придет вам на почту:





Источник: https://sidmid.ru/настройка-alertmanager-prometheus/



2023-01-02T05:34:39
DevOps

Примеры запросов к метрикам Prometheus

Синтаксис запросов




Рассмотрим синтаксис некоторых функций, которые мы будем использовать в нашей инструкции. Проверять все наши запросы можно в веб-интерфейсе прометеуса на странице /graph.




irate или rate




В Prometheus значения для счетчиков всегда возрастают, но как правило, нам нужно знать изменение значения за определенный момент времени. Запрос будет выглядеть так:




irate(<запрос на выборку метрики>[интервал времени, на протяжении которого происходят изменения метрики])




avg by




Среднее значение по условию, например:




avg by (instance)




… среднее для каждого инстанса.




avg_over_time




Среднее значение всех значений для метрик в указанном интервале.




avg_over_time(<запрос на выборку метрики>[интервал])




sum




Функция суммирует полученные результаты:




sum(<запрос на получение значений>)




time




Отображает время в формате UNIX TIME.




time()




count




Считает количество значений:




count(<запрос на получение значений>)




Вместе с by значения могут фильтроваться:




count(<запрос на получение значений>) by (<по какому показателю>)




Арифметические операции




1. С полученными числовыми данными можно выполнять различные математические операции. Например, если мы получим значения времени в секундах, то можно его перевести в часы:




<полученное время> / 60




Или наоборот




<полученное время> * 60




2. Полученный остаток от процентного показателя вычисляется по формуле:




100 — <полученный процент>




Системная информация




Для начала рассмотрим примеры получения общих системных показателей.




Время работы системы




Расчет ведется относительно показателя node_boot_time_seconds (время последнего включения системы).




1. Общее время для всех узлов:




sum(time() — node_boot_time_seconds{})




sum(time() — node_boot_time_seconds{}) / 60




* первый запрос в секундах, второй — в минутах.




2. Для некоторых узлов:




sum(time() — node_boot_time_seconds{instance=~»192.168.0.15:9100|192.168.0.20:9100″})




* в данном примере мы получим сумму значений для узлов 192.168.0.15 и 192.168.0.20.




3. Для всех узлов по отдельности:




time() — node_boot_time_seconds{}




* данный запрос выведет на экран несколько значений для каждого из узлов.




Температура




Данная метрика поддерживается не всем оборудованием или средствами виртуализации.




1. Для всех нод:




node_hwmon_temp_celsius




2. Для конкретных:




node_hwmon_temp_celsius{instance=~’192.168.0.15:9100|192.168.0.20:9100′}




Процессор




Для получения нужных нам показателей будем использовать метрику node_cpu_seconds_total.




Количество процессоров




1. Общее количество всех процессоров всех узлов:




sum(count(node_cpu_seconds_total{mode=’system’}) by (cpu))




2. Для некоторых инстансов:




sum(count(node_cpu_seconds_total{instance=~’192.168.0.15:9100|192.168.0.20:9100′,mode=’system’}) by (cpu))




* для 192.168.0.15 и 192.168.0.20.




3. По отдельности:




count(node_cpu_seconds_total{mode=’system’}) by (instance)




Нагрузка




1. На все ядра всех узлов:




(irate(node_cpu_seconds_total{job=»node_exporter_clients»,mode=»idle»}[5m])) * 100




100 — ((irate(node_cpu_seconds_total{job=»node_exporter_clients»,mode=»idle»}[5m])) * 100)




* первый запрос для отображения процента свободного процессорного времени, второй — процент утилизации.




Пример ответа:




{cpu="0", instance="192.168.0.15:9100", job="node_exporter_clients", mode="idle"} 0.6000000238418579

{cpu="0", instance="192.168.0.20:9100", job="node_exporter_clients", mode="idle"} 0.9999999403953552

{cpu="1", instance="192.168.0.15:9100", job="node_exporter_clients", mode="idle"} 0.6000000238418579

{cpu="1", instance="192.168.0.20:9100", job="node_exporter_clients", mode="idle"} 1.5999999642372131

{cpu="2", instance="192.168.0.15:9100", job="node_exporter_clients", mode="idle"} 0.8000000193715096

{cpu="2", instance="192.168.0.20:9100", job="node_exporter_clients", mode="idle"} 0.8000001311302185

{cpu="3", instance="192.168.0.15:9100", job="node_exporter_clients", mode="idle"} 1.0000000149011612

{cpu="3", instance="192.168.0.20:9100", job="node_exporter_clients", mode="idle"} 0.6000000238418579

{cpu="4", instance="192.168.0.15:9100", job="node_exporter_clients", mode="idle"} 0.19999999552965164

{cpu="4", instance="192.168.0.20:9100", job="node_exporter_clients", mode="idle"} 0.2000001072883606

{cpu="5", instance="192.168.0.15:9100", job="node_exporter_clients", mode="idle"} 0.40000002831220627

{cpu="5", instance="192.168.0.20:9100", job="node_exporter_clients", mode="idle"} 0.3999999165534973

{cpu="6", instance="192.168.0.15:9100", job="node_exporter_clients", mode="idle"} 0.6000000238418579

{cpu="6", instance="192.168.0.20:9100", job="node_exporter_clients", mode="idle"} 0.2000001072883606

{cpu="7", instance="192.168.0.15:9100", job="node_exporter_clients", mode="idle"} 0.19999999552965164

{cpu="7", instance="192.168.0.20:9100", job="node_exporter_clients", mode="idle"} 0.3999999165534973




2. Средняя величина по ядрам для всех узлов:




avg by (instance)(irate(node_cpu_seconds_total{job=»node_exporter_clients»,mode=»idle»}[5m])) * 100




100 — (avg by (instance)(irate(node_cpu_seconds_total{job=»node_exporter_clients»,mode=»idle»}[5m])) * 100)




* первый запрос для отображения процента свободного процессорного времени, второй — процент утилизации.




Пример ответа:




{instance="192.168.0.15:9100"} 0.7999999960884452

{instance="192.168.0.20:9100"} 0.9500000253319598




3. Средняя величина по ядрам для конкретного узла:




avg by (instance)(irate(node_cpu_seconds_total{instance=»192.168.0.15:9100″,job=»node_exporter_clients»,mode=»idle»}[5m])) * 100




100 — (avg by (instance)(irate(node_cpu_seconds_total{instance=»192.168.0.15:9100″,job=»node_exporter_clients»,mode=»idle»}[5m])) * 100)




* первый запрос для отображения процента свободного процессорного времени, второй — процент утилизации.




Пример ответа:




{instance=»192.168.0.15:9100″} 1.100000003352747




Время ожидания




Запрос показывает значение в процентном эквиваленте для времени ожидания процессора. На практике, идеально, когда он равен нулю.




1. Среднее значение за 30 минут для всех узлов:




avg(irate(node_cpu_seconds_total{mode=»iowait»}[30m])) * 100




2. Для конкретного узла:




avg(irate(node_cpu_seconds_total{instance=~»192.168.0.15:9100|192.168.0.20:9100″,mode=»iowait»}[30m])) * 100




3. Отдельно по каждой ноде:




irate(node_cpu_seconds_total{mode=»iowait»}[30m]) * 100




Оперативная память




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







Рассмотрим примеры.




Объем памяти




1. Для всех узлов:




sum(node_memory_MemTotal_bytes{})




2. Для некоторых:




sum(node_memory_MemTotal_bytes{instance=~»192.168.0.15:9100|192.168.0.20:9100″})




3. По отдельности:




node_memory_MemTotal_bytes{}




Использование памяти




1. Свободно:




100 * (1 — ((avg_over_time(node_memory_MemFree_bytes[5m]) + avg_over_time(node_memory_Cached_bytes[5m]) + avg_over_time(node_memory_Buffers_bytes[5m])) / avg_over_time(node_memory_MemTotal_bytes[5m])))




2. Занято:




100 * ((avg_over_time(node_memory_MemFree_bytes[5m]) + avg_over_time(node_memory_Cached_bytes[5m]) + avg_over_time(node_memory_Buffers_bytes[5m])) / avg_over_time(node_memory_MemTotal_bytes[5m]))




Пример ответа:




{instance="192.168.0.15:9100", job="node_exporter_clients"} 41.96494651116369

{instance="192.168.0.20:9100", job="node_exporter_clients"} 10.573695601658944




Сеть




Мы будем использовать метрики:







Примеры ниже.




Передача данных




1. Входящий трафик за последние 5 минут:




rate(node_network_receive_bytes_total[5m]) * 8 / 1024 / 1024




2. Иcходящий трафик за последние 5 минут:




rate(node_network_transmit_bytes_total[5m]) * 8 / 1024 / 1024




Дисковый накопитель




Используемые метрики:







Переходим к примерам.




Объемы




1. Объем разделов:




node_filesystem_size_bytes{instance=~’192.168.0.15:9100|192.168.0.20:9100′,fstype=~»ext4|xfs»}




node_filesystem_size_bytes{fstype=~»ext4|xfs»}




* для конкретных нод или всех.




2. Объем доступного пространства:




node_filesystem_avail_bytes {fstype=~»ext4|xfs»}




3. Объем в процентах.




Используется:




1 — (node_filesystem_free_bytes{fstype=~»ext4|xfs»} / node_filesystem_size_bytes{fstype=~»ext4|xfs»})




Свободно:




node_filesystem_free_bytes{fstype=~»ext4|xfs»} / node_filesystem_size_bytes{fstype=~»ext4|xfs»}




Нагрузка




1. Чтение в килобайтах:




rate(node_disk_read_bytes_total{instance=»Server10:9100″, device=»sda»}[5m]) / 1024




irate(node_disk_read_bytes_total{}[30m]) / 1024




* для конкретного сервера / диска и для всех серверов и всех дисков.




2. Запись в килобайтах:




rate(node_disk_written_bytes_total{instance=»Server10:9100″, device=»sda»}[5m]) / 1024




irate(node_disk_written_bytes_total{}[30m]) / 1024




* для конкретного сервера / диска и для всех серверов и всех дисков.




Источник: https://sidmid.ru/примеры-запросов-к-метрикам-prometheus/



Prometheus: Recording Rules и теги – разделяем алерты в Slack

Необходимо создать отдельные каналы для backendwebgaming, и их алерты вынести в разные каналы Slack. Тогда бекенд-девелоперы будут знать, что если в их канал Слака прилетел алерт – то на него таки стоит обратить внимание.




Как реализуем: используем Prometheus Recording Rules для правил, что бы создать отдельные алерты. Каждый алерт будет создаваться со своим набором тегов, используя которые мы в Opsgenie будем разруливать алерты через разные Slack-интергации по разным каналам.




Prometheus Recording Rules




Recording Rules позволяют формировать правила с expression, которые потом можно использовать в алертах.




К примеру, у нас есть такой алерт:




- name: Endpoint.rules



  rules:



  - record: blackbox_probe:http_probe

    expr: probe_success{instance!~".*stage.*"}

   

  - alert: EndpointProbeSuccess

    expr: blackbox_probe:http_probe != 1

    for: 2m

    labels:

      severity: warning

    annotations:

      summary: 'Endpoint down'

      description: 'Cant access endpoint `{{ $labels.instance }}`'

      tags: http



  - alert: EndpointProbeSuccess

    expr: blackbox_probe:http_probe != 1

    for: 5m

    labels:

      severity: critical

    annotations:

      summary: 'Endpoint down'

      description: 'Cant access endpoint `{{ $labels.instance }}`!'

      tags: http




Тут используя общее правило blackbox_probe:http_probe мы создаём два алерта – один сработает с уровнем P3/warning через 2 минуты, а второй – с уровнем P1/critical через 5 минут, если первый не закрыли.




Prometheus Tags




Собственно говоря, тут теги – это просто дополнительное поле в аннотациях.




В конфиге Alertmanager для reciever Opsgenie настроена передача этих тегов – tags: "{{ .CommonAnnotations.tags}}":




- name: 'warning'

  opsgenie_configs:

    - message: "{{ .CommonAnnotations.summary }}"

      description: "{{ range .Alerts }}nn{{ .Annotations.description }}{{ end }}n*Source*: <{{ (index .Alerts 0).GeneratorURL }}|Prometheus alerts>"

      source: "{{ (index .Alerts 0).GeneratorURL }}"

      tags: "{{ .CommonAnnotations.tags}}"

      priority: P3




И затем эти теги доступны в Opsgenie:





А значит – мы их сможем использовать в фильтрах Slack-интеграций.




AWS CloudWatch Tags?




А что делать с CloudWatch? В Opsgenie есть отдельные интеграции с AWS CloudWatch, которые триггерят свои алерты.




Увы – к CloudWatch Alarms теги прикрутить нельзя (пока что? не нашёл как?), поэтому делаем через теги в самой интеграции.




Например, для AWS Trusted Advisor заданы такие теги:





Позже можно будет разруливать между каналами типа #devops-alarms-aws и #devops-alarms-security.




Настройка Prometheus alerts




Настроим общий Recording Rule, и используя его – создадим два алерта, которые будут выбирать метрики, используя label namespace:





Тут очень пригодилось то, что мы изначально в имена неймспейсов Kubernetes включаем и кластер (devstageprod), и команду, которая этот Namespace создавала.




Например, в имени namespace=prod-cn-1-18-backend-rabbitmq-ns мы видим, что это Prod-кластер в Китае (cn), версия Kubernetes в нём – 1.18, команда, которая использует этот сервис – backend, ну и имя самого сервиса – rabbitmq.




А затем к каждому алерту мы навесим свои теги – backend и web.




Итак, создаём Recording Rule с именем test:eks:pod_restarts:rate:




groups:



###############

### Testing ###

###############



- name: Test.rules



  rules:



  - record: test:eks:pod_restarts:rate

    expr: rate(kube_pod_container_status_restarts_total{ekscluster=~"prod-.*"}[15m]) * 900




Само выражение нам сейчас не особо важно, тут просто скопировал правило из алерта рестартов подов.




Далее, используя этот rule описываем два алерта:




groups:



###############

### Testing ###

###############



- name: Test.rules



  rules:



  - record: test:eks:pod_restarts:rate

    expr: rate(kube_pod_container_status_restarts_total{ekscluster=~"prod-.*"}[15m]) * 900



  - alert: "TestingAlertBackend"

    expr: test:eks:pod_restarts:rate{namespace=~".*backend.*"} < 2

    for: 1s

    labels:

      severity: warning

    annotations:

      summary: "Testing alert: Backend"

      description: "Ignore it: testing alerting system"

      tags: backend, eks



  - alert: "TestingAlertWeb"

    expr: test:eks:pod_restarts:rate{namespace=~".*web.*"} < 2

    for: 1s

    labels:

      severity: warning

    annotations:

      summary: "Testing alert: Web"

      description: "Ignore it: testing alerting system"

      tags: web, eks




Тут в алерте TestingAlertBackend используем правило test:eks:pod_restarts:rate, и выбираем все неймспейсы, которые содержат имя backend:




test:eks:pod_restarts:rate{namespace=~".*backend.*"}




А затем к этому алерту добавляем два тега – backend и eks.




Аналогично – с алертом для Web-team.




Alertmanager group_by




Кроме того, добавим в параметр group_by Алертменеджера группировку по тегам, что бы алерты Backend отделялись от алертов Web:




route:



  group_by: ['alertname', 'tags']

  repeat_interval: 15m

  group_interval: 5m




Иначе, если группировать только по alertname, Alertmanager сгенерирует один алерт, который упадёт в первый попавшийся канал.




Переходим к Opsgenie.




Настройка Opsgenie и Slack




Создаём два канала в Slack – #devops-alarms-backend и #devops-alarms-web – будем их использовать в двух интеграциях Slack.




Далее, добавляем саму первую интеграцию Slack, для Backend-team, и в его Alert Filter выбираем алерты уровня P3 и с тегом backend:





А в старой интеграции – #devops-alarms-warning – добавляем фильтр с NOT, что бы не дублировать алерты в старый канал:





Проверяем – триггерим алерт, и получаем пачку алертов в оба канала.




Бекенд:





Тут Tags: backend, eks.




И аналогичная пачка прилетела от подов веб-команды:





Готово




Источник: https://sidmid.ru/prometheus-recording-rules-и-теги-разделяем-алерты-в-slack/



2023-01-02T05:29:16
DevOps

2. Практика — запуск сервисов Traefik

Traefik – это обратный прокси с поддержкой Docker, который предоставляет встроенную панель мониторинга.




Проект Traefik предоставляет официальный образ Docker, который поможет быстро запустить Traefik в контейнере Docker.




Панель инструментов представляет собой отдельное веб-приложение, которое будет работать в контейнере Traefik по порту 8080.




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




docker -v
Docker version 19.03.1, build 74b1e89
docker-compose -v
docker-compose version 1.22.0, build f46880fe




cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.1.170 test.ru nginx.test.ru nginx2.test.ru




cat docker-compose.yml




version: '2.4'



services:

  traefik:

    image: traefik

    volumes:

       - /var/run/docker.sock:/var/run/docker.sock

    command:  --web

              --defaultentrypoints=http

              --entrypoints="Name:http Address::80"

              --docker

              --docker.endpoint="unix:///var/run/docker.sock"

              --docker.watch=true

              --docker.exposedbydefault=false

    ports:

       - 80:80

       - 8080:8080

  nginx:

    image: nginx:alpine

    container_name: webserver

    restart: unless-stopped

    labels:

    - traefik.frontend.rule=Host:nginx.test.ru

    - traefik.docker.network=traefik

    - traefik.port=80

    - traefik.enable=true

  nginx2:

   image: nginx:alpine

   volumes:

     - /var/www/nginx:/usr/share/nginx/html

   container_name: webserver2

   restart: unless-stopped

   labels:

    - traefik.frontend.rule=Host:nginx2.test.ru

    - traefik.docker.network=traefik

    - traefik.port=80

    - traefik.enable=true<br /><br /></code><span style="font-family: georgia, palatino, serif;">В данном конфиге мы запускаем 3 сервиса, 1 - traefik, 2,3 - контейнеры nginx.</span>




У traefik только 1 точка входа, это 80 порт. На порту 8080 будет доступна панель в которой визуально отображается какие сервисы доступны.
Для поднимаемых нами сервисов указаны следующие доменные имена: nginx.test.ru и nginx2.test.ru,они используют созданную ранее docker сеть traefik
и как мы видим, отвечают по одному 80 порту.  Для того чтобы работал сервис работал ему прописывается пункт label где задаются параметры для traefik.
Ниже показан ответ curl по нашим сервисам:




curl nginx.test.ru



Спойлер