Привет! В этой заметке поговорим о мониторинге.

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

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

Настройка Prometheus, Grafana, Nginx

Собственно, мы имеем небольшой сервер с установленным docker. (Как установить докер, ссылочка - тык). Далее на сервере создадим структуру, где и будем хранить необходимые файлики.

mkdir /opt/mon/prometheus -p

Каталог /opt/mon будет корневым для всего стека. По ходу написания композ-файла, структура будет наполняться необходимым. Теперь в каталоге для prometheus, создалим базовый конфиг прометея:

vim /opt/mon/prometheus/prometheus.yml
---
global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

  - job_name: 'grafana'
    static_configs:
      - targets: ['grafana:3000']

В этой конфигурации мы глобально задаем интервал сбора данных в 15 секунд. И далее перечисляем два задания (job) для сбора данных с целевых хостов. Этого будет достаточно, для первичного запуска контейнера.

Приступим к написанию композ файла,

services:
  prometheus:
  image: prom/prometheus:latest
  container_name: prometheus
  volumes:
    - /opt/mon/prometheus:/etc/prometheus
    - prometheus_data:/prometheus
  ports:
    - "9090:9090"
  command:
    - '--config.file=/etc/prometheus/prometheus.yml'
    - '--storage.tsdb.path=/prometheus'
    - '--storage.tsdb.retention.time=21d'
  restart: always

volumes:
  prometheus_data:      

Здесь в контексте services вы определяем настройки запуска сервисе - prometheus.

  • image - образ контейнера, для запуска сервиса,
  • container_name - имя для нашего контейнера,
  • volumes - используемые сервисом разделы. В данном случаи мы монтируем две области,
    • /opt/mon/prometheus:/etc/prometheus - раздел с конфигурационными файлами прометея,
    • prometheus_data:/prometheus - тут монтируется том докера, для данных базы прометея,
  • ports - открываем порты для сервиса. Здесь, мы просто пробрасываем порт - 9000:9000 внутрь контейнера
  • command - при помощи этой директивы мы переопределяем параметры запуска контейнера,
    • --config.file=/etc/prometheus/prometheus.yml - тут в качестве аргумента передается конфиг prometheus,
    • --storage.tsdb.path=/prometheus - здесь мы определяем место хранение данных базенки,
    • --storage.tsdb.retention.time=21d - а этот агрумент определяет срок хранения данных, для меня достаточно хранить данные 21 день.
  • restart - определяем политику перезапуска контейнера, в данном случаи он будет перезапускаться, независимо от его причины остановки.

В конец манифеста добавляем контекст с томами:

volumes:
  prometheus_data: 

Запускать эту портянку не имеет смысла, дополним файлик и опишем сервис с графаной:

vim /opt/mon/prometheus/prometheus.yml
---
grafana:
  image: grafana/grafana:latest
  container_name: grafana
  volumes:
    - grafana_data:/var/lib/grafana
  ports:
    - "3000:3000"
  environment:
    - GF_SECURITY_ADMIN_USER=admin
    - GF_SECURITY_ADMIN_PASSWORD=admin
  depends_on:
    - prometheus
  restart: always

Большинство параметров имеют уже знакомые нам свойства:

  • image - образ контейнера из которого будет поднят сервис,
  • container_name - имя запускаемого контейнера
  • volumes - монтируемые в контейнер том,
    • grafana_data:/var/lib/grafana - здесь имеется один том, в котором будут размещаны данные от графаны
  • ports - открываем единственный порт во внутрь контейнера - 3000:3000,
  • environment - определяем переменные окружения, для контейнера. В данной случаи мы передаем первичные данные о логине/пароле в графанку.
  • depends_on - это свойство включает зависимость данного сервиса от другого. В нашем кейсе, графана запуститься, только после успешного старта сервиса prometheus.
  • restart - также разрешаем перезапуск контейнера.

В контексте с томами, добавляем новый том для графаны:

volumes:
  prometheus_data:
  grafana_data: 

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

docker compose -f /opt/mon/docker-compose.yml up -d

Через некоторое время, сервисы будут активны. Удостовериться этом можем командой:

docker compose -f /opt/mon/docker-compose.yml ps
NAME         IMAGE                    COMMAND                  SERVICE      CREATED          STATUS          PORTS
grafana      grafana/grafana:latest   "/run.sh"                grafana      30 minutes ago   Up 30 minutes   0.0.0.0:3000->3000/tcp, :::3000->3000/tcp
prometheus   prom/prometheus:latest   "/bin/prometheus --c…"   prometheus   2 hours ago      Up 2 hours      0.0.0.0:9090->9090/tcp, :::9090->9090/tcp

Что бы не ходить на графану через сервисный порт (3000/TCP), запроксируем доступ на нее через nginx. Для этого вновь открываем docker-compose.yml, и добавляем новый сервис:

nginx:
  image: nginx
  container_name: nginx
  volumes:
    - /opt/mon/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
  ports:
    - "80:80"
  depends_on:
    - grafana
  restart: always

Данный сервис имеет аналогичные свойства, что мы рассмотрели ранее. Если коротко, то мы запускаем сервис из образа - nginx (будет взят самый последний). Имя контейнера будет аналогична названию сервиса. А в параметрах монтирования, мы пробрасываем конфиг nginx.conf с атрибутами read-only. По портам открываем только 80/TCP порт, TLS у меня в локальной сети не настроен. И конце добавляем зависимость от сервиса с графаной, то есть что бы nginx стартанул только после запуска графаны.

Если же сейчас попробуем стартануть обновленный композ, nginx будет перезапускаться, так как мы создали его конфигурацию. Для этого на хостовой файлухе в каталоге с нашим стеком создаем новую директорию и пишем конфигурацию для nginx:

mkdir /opt/mon/nginx
vim /opt/mon/nginx/nginx.conf
---
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /run/nginx.pid;

include /usr/share/nginx/modules/*.conf;

events {
        worker_connections 1024;
}

http {
        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                          '$status $body_bytes_sent "$http_referer" '
                          '"$http_user_agent" "$http_x_forwarded_for"';

        access_log  /var/log/nginx/access.log  main;

        sendfile            on;
        tcp_nopush          on;
        keepalive_timeout   65;
        types_hash_max_size 4096;

        include             /etc/nginx/mime.types;
        default_type        application/octet-stream;

        map $http_upgrade $connection_upgrade {
                default upgrade;
                '' close;
        }

        upstream grafana {
                server grafana:3000;
        }

        server {
                listen 80;

                root /usr/share/nginx/html;
                index index.html index.htm;

                location / {
                        proxy_set_header Host $http_host;
                        proxy_pass http://grafana;
                }

                location /api/live/ {
                        proxy_http_version 1.1;
                        proxy_set_header Upgrade $http_upgrade;
                        proxy_set_header Connection $connection_upgrade;
                        proxy_set_header Host $http_host;
                        proxy_pass http://grafana;
                }
        }
}

Если коротко, этот конфиг имеет только один сервер, который принимает запросы на 80/HTTP порту и перенаправляет их на сервис с графаной.

На хостовой машине добавляем разрешаюшее правило фаервола для http:

firewall-cmd --add-service=http --permanent
firewall-cmd --reload

Затем повторно запускаем compose-файл:

docker compose -f /opt/mon/docker-compose.yml up -d

После инициализации, повторно убеждаемся что контейнер с nginx не падает:

docker compose -f /opt/mon/docker-compose.yml ps | grep nginx
nginx        nginx                    "/docker-entrypoint.…"   nginx        5 minutes ago       Up 5 minutes       0.0.0.0:80->80/tcp, :::80->80/tcp

В браузере переходим по адресу сервера, и попадаем в окно логина grafana: promstack-graff-login Данные логина/пароля используем те, что указали в environment к сервису. После входа меняем пароль, и нас перебросит на основной экран.

Проваливаемся в раздел - Connections > Data sources, где добавим наш сервер prometheus: promstack-graff-ds1

Затем из списка возможных ресурсов, выбираем - Prometheus: promstack-graff-ds2

В окне настроек ресурса, указываем url-адрес prometheus. И опционально, выбираем его как источник по умолчанию. promstack-graff-ds3 Url-адрес содержит название сервиса и порт. За счет внутренней магии docker, сервис разрезолвится корректно.

Сохраняем настройки и переходим к добавлению экспортеров..

Настройка MKTXP

Для сбора метрик с устройств MikroTik есть замечательный экспортер MKTXP. По сути это полноценное контейнерное приложение, которое стягивает данные с сетевых устройств за счет обращения к API RouterOS. Также имеет свой CLI.

Приступаем, для начала на стороне сетевой железки нужно добавить группу и системного пользователя, через которого будет ходить на API микротика. Через Winbox/ssh подключаемся на железку и выполняем команды:

/user group add name=prometheus policy=api,read
/user add name=prometheus group=prometheus password=VeryStrongPassword

Помимо этого, убеждаемся что на микроте включен сервис API, выполняем команду:

[[email protected]] > /ip service/ print where name =api   
Columns: NAME, PORT, VRF, MAX-SESSIONS
# NAME  PORT  VRF   MAX-SESSIONS
5 api   8728  main            20

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

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

mkdir /opt/mon/mktxp

Внутри данной директории, создаем два конфигурационных файла:

  • _mktxp.conf - является базовым конфигом, который настраивает сам экспортер.
  • mktxp.conf - конфигурационный файл, в котором мы определяем наши сетевые устройтства и параметры мониторинга их.

Создаем _mktxp.conf:

vim /opt/mon/mktxp/_mktxp.conf
---
[MKTXP]
    listen = '0.0.0.0:49090'         # Space separated list of socket addresses to listen to, both IPV4 and IPV6
    socket_timeout = 5

    initial_delay_on_failure = 120
    max_delay_on_failure = 900
    delay_inc_div = 5

    bandwidth = True                # Turns metrics bandwidth metrics collection on / off
    bandwidth_test_interval = 1200    # Interval for collecting bandwidth metrics
    minimal_collect_interval = 5     # Minimal metric collection interval

    verbose_mode = False             # Set it on for troubleshooting

    fetch_routers_in_parallel = False   # Fetching metrics from multiple routers in parallel / sequentially
    max_worker_threads = 5              # Max number of worker threads that can fetch routers (parallel fetch only)
    max_scrape_duration = 30            # Max duration of individual routers' metrics collection (parallel fetch only)
    total_max_scrape_duration = 90      # Max overall duration of all metrics collection (parallel fetch only)

    compact_default_conf_values = False  # Compact mktxp.conf, so only specific values are kept on the individual routers' level

Файл стянул с гитхаб репозитория, поменял только - bandwidth и bandwidth_test_interval.

Создаем mktxp.conf:

vim /opt/mon/mktxp/mktxp.conf
---
[r1.home.local]
    hostname = r1.home.local

[default]
    enabled = True          # turns metrics collection for this RouterOS device on / off
    hostname = localhost    # RouterOS IP address
    port = 8728             # RouterOS IP Port

    username = prometheus     # RouterOS user, needs to have 'read' and 'api' permissions
    password = VeryStrongPassword

    use_ssl = False                 # enables connection via API-SSL servis
    no_ssl_certificate = False      # enables API_SSL connect without router SSL certificate
    ssl_certificate_verify = False  # turns SSL certificate verification on / off
    plaintext_login = True          # for legacy RouterOS versions below 6.43 use False

    installed_packages = True       # Installed packages
    dhcp = True                     # DHCP general metrics
    dhcp_lease = True               # DHCP lease metrics

    connections = True              # IP connections metrics
    connection_stats = False        # Open IP connections metrics

    interface = True                # Interfaces traffic metrics

    route = True                    # IPv4 Routes metrics
    pool = True                     # IPv4 Pool metrics
    firewall = True                 # IPv4 Firewall rules traffic metrics
    neighbor = True                 # IPv4 Reachable Neighbors
    dns = False                     # DNS stats

    ipv6_route = False              # IPv6 Routes metrics
    ipv6_pool = False               # IPv6 Pool metrics
    ipv6_firewall = False           # IPv6 Firewall rules traffic metrics
    ipv6_neighbor = False           # IPv6 Reachable Neighbors

    poe = True                      # POE metrics
    monitor = True                  # Interface monitor metrics
    netwatch = True                 # Netwatch metrics
    public_ip = True                # Public IP metrics
    wireless = True                 # WLAN general metrics
    wireless_clients = True         # WLAN clients metrics
    capsman = True                  # CAPsMAN general metrics
    capsman_clients = True          # CAPsMAN clients metrics

    eoip = False                    # EoIP status metrics
    gre = False                     # GRE status metrics
    ipip = False                    # IPIP status metrics
    lte = False                     # LTE signal and status metrics (requires additional 'test' permission policy on RouterOS v6)
    ipsec = False                   # IPSec active peer metrics
    switch_port = False             # Switch Port metrics

    kid_control_assigned = False    # Allow Kid Control metrics for connected devices with assigned users
    kid_control_dynamic = False     # Allow Kid Control metrics for all connected devices, including those without assigned user

    user = True                     # Active Users metrics
    queue = True                    # Queues metrics

    bgp = False                     # BGP sessions metrics
    routing_stats = False           # Routing process stats
    certificate = False             # Certificates metrics

    remote_dhcp_entry = None        # An MKTXP entry to provide for remote DHCP info / resolution
    remote_capsman_entry = None     # An MKTXP entry to provide for remote capsman info

    use_comments_over_names = True  # when available, forces using comments over the interfaces names
    check_for_updates = False       # check for available ROS updates

Тут тоже большинство параметров оставил по умолчанию. Вначале добавил контекст с именем маршрутизатора, внутри контекста указал ip-адрес.

[r1.home.local]
    hostname = r1.home.local # Можно указать IP или FQDN

В контексте default, нужно указать свои данные логина/пароля. Те, что мы создавали на стороне железки..

[default]
    ....
    username = prometheus
    password = VeryStrongPassword

Подготовительные настройки соблюдены, теперь остается только дополнить композ-файл новым сервисом.

vim /opt/mon/docker-compose.yml
---
mktxp:
  image: ghcr.io/akpw/mktxp:latest
  container_name: mktxp
  user: root
  volumes:
    - /opt/mon/mktxp/:/root/mktxp/
  ports:
    - "49090:49090"
  restart: unless-stopped

В описании сервиса, уже знакомые нам директивы. Стоит обратить внимание, на монтирование. Ранее подготовленные конфиги монтируем во внутрь контейнера до /root/mktxp/. И запускаем процесс из под пользователя root.

Запускаем обновленный - docker-compose.yml:

docker compose -f /opt/mon/docker-compose.yml up -d

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

vim /opt/mon/prometheus/prometheus.yml
---
global:
  scrape_interval: 15s

scrape_configs:
  ...
  - job_name: 'mktxp'
    static_configs:
      - targets: ['mktxp:49090']

В конец файла добавляем новый джоб с именем - mktxp, а в таргетах указываем название сервиса с экспортером и порт.

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

docker compose -f /opt/mon/docker-compose.yml restart prometheus

В графане, раздел Dasboadrds делаем импорт этого дашборда, и получаем такую красоту: promstack-graff-mktxp.png

Настройка PVE exporter

Снимать метрики с виртуальных хостов под управлением Proxmox будем через - Proxmox VE Exporter. Экспортер дергает данные посредством обращений к API Proxmox и преобразует их в формат понятный для prometheus.

Для доступа к API, будем использовать токен.

Чтобы его выпустить подключаемся в web-консоль proxmox хоста, и проваливаемся в меню - Datacenter > Permissions > API Tokens: promstack-graff-prx1.png После нажатия кнопки - Add, в появившемся окне прописываем внятный ID для токена и жмем на - Добавить.

В следуюшем окне будет отображена информация по самому токену, секрет временно сохраняем у себя.

Далее в корневом каталоге стека, вновь создаем директорию под конфиг экспортера:

mkdir /opt/mon/pve

Внутри его создаем файлик:

vim /opt/mon/pve/pve.yml
---
default:
    user: prometheus@pve
    token_name: "pve-exporter"
    token_value: "<ВСТАВИТЬ SERCET>"
    verify_ssl: false

Данные для подключения, что были созданы ранее, прописываем в этом файле.

Обновляем композ файл:

vim /opt/mon/docker-compose.yml
---
pve:
  image: prompve/prometheus-pve-exporter
  container_name: pve
  volumes:
    - /opt/mon/pve/pve.yml:/etc/prometheus/pve.yml
  ports:
    - "9221:9221"
  command:
    - '--config.file=/etc/prometheus/pve.yml'
  restart: unless-stopped

В параметрах данного сервиса, монтируем во внутрь контейнера настройки подключения к хосту. Открываем порт - 9221/TCP и для запуска процесса передаем агрумент с указанием конфигурационного файла.

Запускаем обновленный композник:

docker compose -f /opt/mon/docker-compose.yml up -d

Обновляем prometheus.yml:

vim /opt/mon/prometheus/prometheus.yml
---
scrape_configs:
  ...
  - job_name: 'pve'
    static_configs:
      - targets:
        - prx01.home.local  # Proxmox VE node.
    metrics_path: /pve
    params:
      module: [default]
      cluster: ['1']
      node: ['1']
    relabel_configs:
      - source_labels: [__address__]
        target_label: __param_target
      - source_labels: [__param_target]
        target_label: instance
      - target_label: __address__
        replacement: pve:9221  # PVE exporter.

В контексте перечисление таргетов (targets), указываем адреса хостов Proxmox. Адрес экспортера прописываем в контексте relabel_config > replacement.

Перезапускаем прометей, и идем добавлять дашбоард:

docker compose -f /opt/mon/docker-compose.yml restart prometheus

Дашборд скачиваем отсюда, и по итогу имеем: promstack-graff-prx2.png

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

Настройка Speedtest

Следующий экспортер который был бы полезен - speedtest-exporter. Думаю что у большинства людей уже был опыт использования этого сервиса, который помогает с замерами полосы пропускания предоставляемой провайдером.

Экспортер работает поверх утилиты - Speedtest CLI.

Добавим новый сервис в docker-compose.yml:

vim /opt/mon/docker-compose.yml
---
speedtest:
  image: ghcr.io/miguelndecarvalho/speedtest-exporter
  container_name: speedtest
  ports:
    - "9798:9798"
  restart: unless-stopped

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

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

docker compose -f /opt/mon/docker-compose.yml up -d

Не забываем обновить конфигу prometheus, к ней добавится новый джобик:

vim /opt/mon/prometheus/prometheus.yml
---
scrape_configs:
  ...
  - job_name: 'speedtest'
    scrape_interval: 1h
    scrape_timeout: 3m
    static_configs:
      - targets: ['speedtest:9798']

Обратите внимание на интервалы, мне не нужно выполнять проверки скорости слишком часто. Поэтому в scrape_interval указано значение в один час.

Перезапускаем сервис с прометеeм:

docker compose -f /opt/mon/docker-compose.yml restart prometheus

Переключаемся на графану, и импортируем эту дешку. Данные на графиках появятся не сразу, так как у нас установлен жирный интервал. Но по итогу, примерно такое отображение: promstack-graff-speed.png

Настройка BlackBox

Доступность удаленных ресурсов и актульность SSL-сертификатов будем мониторить через BlackBox exporter. Ранее эта тема обсуждалась подробнее в рамках прошлых заметок.

Для деплоя контейнера с экспортером, возвращаемся на сервера мониторинга и в корневом каталоге нашего стека создаем новый каталог:

mkdir /opt/mon/blackbox

Внутри нового каталога пишем конфигу для blackbox

vim /opt/mon/blackbox/blackbox.yml
---
modules:
  http_2xx:
    prober: http
    timeout: 5s
    http:
      method: GET
      follow_redirects: true
      fail_if_ssl: false
      fail_if_not_ssl: false
      tls_config:
        insecure_skip_verify: false
      preferred_ip_protocol: "ip4" # defaults to "ip6"

Внутри конфигурационного файла следует перечисление модулей, в моей случаи мне достаточно одного - http_2xx. Относительно остальных можно почитать в документации. Свойства описанных в контексте модуля, настраивают логику его работы:

  • prober - тип проверки, http/tcp..
  • timeout - период в течении которого проба будет ожидать ответа от удаленной точки,
  • http - внутри этого контекста уже настраиваются параметры http-пробы. Если коротко, тут мы указаваем используемы метод для http-запроса (method: GET), потом разрешаем следовать редиректам - follow_redirects: true. В конце отключаем строгу проверку по tls, и указываем предпочтительную версую протокола ip.

Дополним файл docker-compose.yml новым сервисом:

blackbox:
  image: quay.io/prometheus/blackbox-exporter:latest
  container_name: blackbox
  volumes:
    - /opt/mon/blackbox/blackbox.yml:/config/blackbox.yml
  ports:
    - "9115:9115"
  command:
    - '--config.file=/config/blackbox.yml'
  restart: unless-stopped

Свойства данного сервиса уже тривиальны, поэтому идем далее.

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

scrape_configs:
  ...
  - job_name: 'blackbox'
    metrics_path: /probe
    params:
      module: [http_2xx]
    static_configs:
      - targets:
        - https://example.com
        - https://ya.ru
        - https://nixhub.ru
    relabel_configs:
      - source_labels: [__address__]
        target_label: __param_target
      - source_labels: [__param_target]
        target_label: target
      - target_label: __address__
        replacement: blackbox:9115

В параметрах (params) выделяем, каким модулем будем выполнять проверки. Список ресурсов определяем в таргетах - targents. Значение для replacement должно состоять из названия сервиса и порта к экспортеру.

Запускаем обновленный композ файл:

docker compose -f /opt/mon/docker-compose.yml up -d

Потребуется также перезапустить контейнер с прометеем:

docker compose -f /opt/mon/docker-compose.yml restart prometheus

На выбор под этот экспортер можно найти несколько дашбордов. Имхо, практичным показался этот.

Импортом добавляем его, и проверяем корректность инсталяции. promstack-graff-bx.png

Как дополнение, уже к текущему списку сервисов можно/нужно добавить экспортеры - node_exporter и cAdvisor. Для того что бы мониторить операционки и контейнеры. Но из-за большого количества объектов в инфраструктуре проще всего настраивать их посредством ansible или puppet. Возможно позже, проработаю эту тему.

Нотификации и алертинг

Информацию по проблемам будем отправлять в телеграмм через alertmanager, поэтому вам предварительно потребуется создать телеграмм-бота, получить данные - API Token и CHAT ID telegram.

Развертывание alertmanager начинаем с создания отдельного каталога в директории со стеком.

mkdir /opt/mon/alertmanager

Внутри данного каталога создаем конфигу:

vim /opt/mon/alertmanager/alertmanager.yml
---
[root@mon ~]# cat /opt/mon/alertmanager/alertmanager.yml
---
route:
  group_by: ['alertname']
  group_wait: 30s
  group_interval: 30s
  repeat_interval: 10m
  receiver: 'telegram-api'
receivers:
  - name: 'telegram-api'
    telegram_configs:
    - bot_token: '<СЮДА ТОКЕН БОТА>'
      api_url: 'https://api.telegram.org'
      chat_id: <СЮДА ID ЧАТА> # Например, в формате -100XXXXX0XX58
      parse_mode: ''
      message: "Alertmanager 📛\n--\n🔺 Alert: {{ .GroupLabels.alertname}}\n🔺 Severity: {{ .CommonLabels.severity }}\n📌 {{ range .Alerts }}{{ .Annotations.summary }}\n{{ end }}"

В этом конфигурационном файле два контекста. Первый route настраиваем параметры выбора нужного маршрута для отправки алерта, будь это почта, слак или телеграм. Вторый контескт receivers, содержит список получателей.

В нашем случаи используется один это - telegram-api. В его параметрах мы указываем значения для bot_token - токен для бота. Также задаем значение для - chat_id. Можно обратить внимание на параметр - message, который содержит шаблон для формата сообщения.

Все настройки для alertmanager выполнены, теперь можем подправить файл композа и добавить в него новый сервер:

alertmanager:
  image: quay.io/prometheus/alertmanager
  container_name: alertmanager
  volumes:
    - /opt/mon/alertmanager/alertmanager.yml:/config/alertmanager.yml
  ports:
    - "9093:9093"
  command:
    - '--config.file=/config/alertmanager.yml'
   restart: always

В параметрах сервиса нет нечего для нас нового, поэтому просто поднимаем сервис:

docker compose -f /opt/mon/docker-compose.yml up -d

На стороне прометея потребуется настроить интеграцию с alertmanager, для этого в его конфигу добавляем:

vim /opt/mon/prometheus/prometheus.yml
---
alerting:
  alertmanagers:
    - static_configs:
      - targets:
        - alertmanager:9093

rule_files:
  - rules/blackbox.yml
# - rules/example.yml

Следом за глобальными настройками, в поле alerting прописываем адрес и порт к alertmanager. Ниже опеределяем список, который будет содержать правила/триггеры для срабатывания уведомлений.

Под правила/триггеры потребуется создать отдельный каталог в папке с конфигами prometheus:

mkdir /opt/mon/prometheus/rules

В этом же каталоге создаем правиля для алертинга по blackbox-эспортеру. Я не стал придумывать что то новое и просто скопировал данные из прошлой своей заметки:

vim /opt/mon/prometheus/rules/blackbox.yml
---
groups:
- name: alerts
  rules:
  - alert: EndpointDown
    expr: probe_success == 0
    for: 10s
    labels:
      severity: "critical"
    annotations:
      summary:
        "Endpoint {{ $labels.target }} is down."
  - alert: SSLCertExpire
    expr: probe_ssl_earliest_cert_expiry{job="blackbox"} - time() < 86400 * 3
    for: 5m
    labels:
      severity: "warning"
    annotations:
      summary: "SSL certificate will expire in {{ $value | humanizeDuration }} (endpoint {{ $labels.target }})"

Здесь описаны параметры оповещения для двух проблем. Первое, это когда удаленный хост недоступен. И второе, когда ssl-сертификат удаленного хоста истекает.

По этому же примеру можно будет создать триггеры для pve и mktp экспортеру.

Теперь перезапускаем прометеус и проверяем доставку алертов:

docker compose -f /opt/mon/docker-compose.yml restart prometheus

Заключение

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

Заключительным действием, имеет место быть завернуть запуск сервисов во внутрь systemd-юнит.

vim /etc/systemd/system/promstack.service
---
[Unit]
Description=PromStack over docker compose
PartOf=docker.service
After=docker.service

[Service]
Type=oneshot
RemainAfterExit=true
WorkingDirectory=/opt/mon
ExecStart=/usr/bin/docker compose up -d --remove-orphans
ExecStop=/usr/bin/docker compose down

[Install]
WantedBy=multi-user.target

Добавляем в автозагрузку сервис в автозагрузку.

systemctl enable promstack

Все файлики приложил к гитхаб репозиторию.