Сегодня появилась задачка настроить мониторинг внешних web-сервисов из вне инфраструктуры.
Условно запускаем инстанс где-нибудь на digital ocean, и начинаем выполнять пробы (проверки) на внешний контур инфры - http, ssh и прочее.
Таска достаточно простая, развернул забикс напихал туда проверок и поехали. Но хочется чего нибудь не тривиального и модного =)
Вообщем пришла идея попробовать развернуть схему Blackbox Exporter + Prometheus.
blackbox_exporter - экспортер позволяющий нам снимать метрики с эндпоинтов поверх протоколов http, icmp, tcp, grpc и прочего. Что касается метрик, то получаем данныe по статусу конечной точки (доступна/недоступна), время ее отклика. И самое вкусное это дата истечение ssl сертификатов.
(Workflow всей схемы)
Установка экспортера
Идем на github репозиторий и находим там последний релиз: https://github.com/prometheus/blackbox_exporter/releases/
Последний 0.23.0 / 2022-12-02
, выбираем совместимый с нашей системой архив и качаем его на удаленный сервер:
[root@mon ~]# cd /opt/
[root@mon opt]# wget https://github.com/prometheus/blackbox_exporter/releases/download/v0.23.0/blackbox_exporter-0.23.0.linux-amd64.tar.gz
Распаковываем архив и проваливаемся внутрь:
[root@mon opt]# tar -zxvf blackbox_exporter-0.23.0.linux-amd64.tar.gz
[root@mon opt]# cd blackbox_exporter-0.23.0.linux-amd64
Архив будет содержать бинарь с экпортером и файл конфигурации. В файле конфигурации описываются модули и пробы для проверок. По умолчанию, в конфиге прописаны почти все доступные пробы (http, tcp, grpc, ssh и прочее).
Создадим новый сервис для запуска експортера, сначала добавляем нового системного пользователя:
[root@mon ~]# useradd -c "Blackbox exporter user" -U --system -s /bin/false blackbox
В /etc
добавляем каталог под конфигурации blackbox, и копируем туда конфиг:
[root@mon ~]# mkdir /etc/blackbox
[root@mon ~]# cp /opt/blackbox_exporter-0.23.0.linux-amd64/blackbox.yml /etc/blackbox/
И не забываем сменить владельца/группы:
[root@mon ~]# chown -R blackbox:blackbox /etc/blackbox/
Бинарь с экспортером также закидываем в каталог - /usr/local/bin
. И также меняем владельца/группу:
[root@mon ~]# cp /opt/blackbox_exporter-0.23.0.linux-amd64/blackbox_exporter /usr/local/bin/
[root@mon ~]# chown -R blackbox:blackbox /usr/local/bin/blackbox_exporter
Напишем systemd юнит, для сервиса:
[root@mon ~]# vim /etc/systemd/system/blackbox.service
---
[Unit]
Description=Blackbox Exporter Service
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
User=blackbox
Group=blackbox
ExecStart=/usr/local/bin/blackbox_exporter \
--config.file=/etc/blackbox/blackbox.yml \
--web.listen-address="127.0.0.1:9115"
Restart=always
[Install]
WantedBy=multi-user.target
Релоудим systemd и запускаем сервис:
[root@mon ~]# systemctl daemon-reload
[root@mon ~]# systemctl enable --now blackbox
Если на этом этапе нечего не закрашилось, можем перейти к тестированию работы экспортера.
Для проверки экспортера, достаточно кинуть curl запрос:
[root@mon ~]# curl http://localhost:9115/metrics
[root@mon ~]# curl 'localhost:9115/probe?target=ya.ru&module=http_2xx'
В результате выполнения команды, будет вывод с кучей метрик.
На страничке браузера будет опубликована страничка с результатами проб, и описанием конфигурации:
Как я и говорил ранее по умолчанию в конфиге указано излишне проб. Для моей задачи достаточно настроить модуль http. Поэтому в конфиге удаляем все лишнее, и обновляем модули:
[root@mon ~]# vim /etc/blackbox/blackbox.yml
---
modules:
http_2xx:
prober: http
timeout: 5s
http:
valid_http_versions: ["HTTP/1.1", "HTTP/2.0"]
valid_status_codes: [] # Defaults to 2xx
method: GET
headers:
Accept-Language: en-US
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"
ip_protocol_fallback: false # no fallback to "ip6"
modules
- Основное поле, содержащее список модулей.http_2xx:
- Имя модуля.prober
- В значение этой директивы указывается тип пробы (http, tcp, etc..).timeout
- Как понятно из название это таймаут, здесь указывается время в секундах. Через сколько секунд проба будет отброшена, в случаи долгово ожидания.http:
- Внутри этого контекста описывается конфиграция http пробы.valid_http_versions
- Указываются валидные версии http для этой пробы.valid_status_codes
- В этом поле указываются валидные коды ответов, по умолчанию это 200 status code.method
- Метод http запроса, по умолчанию это get-запрос.headers
- Тут перечисляются передаваемые в запросе хедеры.follow_redirects
- Здесь разрешаем или запрешаем редиректы для проб.fail_if_ssl
- Проба будет отброшена, если у конечной точки представлен ssl.fail_if_not_ssl
- Проба сфейлится, если у конечной точки ssl не представлен.tls_config
- В этом блоке описываеются конфигурация для tls.preferred_ip_protocol
- какую версию ip используем в этом модуле. по умолчанию тут ipv6.
Перезапускаем экспортера, и делаем тест пробы:
[root@mon ~]# systemctl restart blackbox
Тестовый запрос:
[root@mon ~]# curl 'localhost:9115/probe?target=https://example.com&module=http_2xx'
---
ts=2023-04-25T17:34:58.824445326Z caller=main.go:181 module=http_2xx target=https://example.com level=info msg="Probe succeeded" duration_seconds=0.702091381
В результате вывода, отображаются уже другие значения у метрик.
Установка prometheus
Скрапить данные данные будем через прометеус, установим это на этот же сервер и далее сбиндим с экпортером.
Под сервис с прометеусом создаем еще одного системного пользователя:
[root@mon ~]# useradd -c "Prometheus system user" -U --system -s /bin/false prometheus
Создаем новые каталоги под нужды сервиса, требуется директории для конфигов и данных прометеуса:
# Каталог для данных
[root@mon ~]# mkdir /var/lib/prometheus
# Каталоги под конфиги
[root@mon ~]# mkdir -p /etc/prometheus/{rules,rules.d,files_sd}
Теперь идем на сайт, выбираем и качаем последний билд под нашу систему - https://prometheus.io/download/
:
[root@mon ~]# cd /opt/
[root@mon opt]# wget https://github.com/prometheus/prometheus/releases/download/v2.37.6/prometheus-2.37.6.linux-amd64.tar.gz
Распаковываем архив:
[root@mon opt]# tar -zxvf prometheus-2.37.6.linux-amd64.tar.gz
Копируем бинари:
[root@mon opt]# cd prometheus-2.37.6.linux-amd64
[root@mon prometheus-2.37.6.linux-amd64]# cp prometheus promtool /usr/local/bin/
Конфиги со смежными зависимостями закидываем в конфигурационный конфиг prometheus:
[root@mon prometheus-2.37.6.linux-amd64]# cp -r prometheus.yml consoles/ console_libraries/ /etc/prometheus/
Сразу же меняем пользователя/группу на каталогах:
[root@mon ~]# chown -R prometheus:prometheus /etc/prometheus
[root@mon ~]# chown -R prometheus:prometheus /var/lib/prometheus/
[root@mon ~]# chmod -R 774 /etc/prometheus
Ну и для запуска всего создаем systemd юнит:
[root@mon ~]# vim /etc/systemd/system/prometheus.service
---
[Unit]
Description=Prometheus
Documentation=https://prometheus.io/docs/introduction/overview/
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
User=prometheus
Group=prometheus
ExecReload=/bin/kill -HUP $MAINPID
ExecStart=/usr/local/bin/prometheus \
--config.file=/etc/prometheus/prometheus.yml \
--storage.tsdb.path=/var/lib/prometheus \
--web.console.templates=/etc/prometheus/consoles \
--web.console.libraries=/etc/prometheus/console_libraries \
--web.listen-address=127.0.0.1:9090 \
--web.external-url=
SyslogIdentifier=prometheus
Restart=always
[Install]
WantedBy=multi-user.target
Релоудим и запускаем прометеус:
[root@mon ~]# systemctl daemon-reload
[root@mon ~]# systemctl enable --now prometheus
По умолчанию, сейчас в конфиге прописана только одна цель для скрапинга метрик это сам прометеус. Отредактируем его конфиг, и добавим вторую цель с ссылкой на установленный ранее экспортер. Редактируем конфиг:
[root@mon ~]# vim /etc/prometheus/prometheus.yml
---
- job_name: 'blackbox'
metrics_path: /probe
params:
module: [http_2xx]
static_configs:
- targets:
- https://example.com
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: 127.0.0.1:9115
В поле static_configs
> targets
далее будем добавлять наши конечные точки. Сейчас для проверки я указал сайт заглушку.
static_configs:
- targets:
- https://example.com
Перезапускаем, сервис с прометеусом.
[root@mon ~]# systemctl restart prometheus
На этом все, теперь можем сходить в WebUI прометеуса и чекнуть работу наших проб:
Настройка Grafana
Ну и почти заключительным этапом поставим графану, и прикрутем к ней прометеус. Идем на сайт https://packages.grafana.com/
, для получени файла конфигурации нового репозитория. На сайте копируем данные, и вставляем в файл с описанием репы:
[root@mon ~]# cat /etc/yum.repos.d/grafana.repo
---
[grafana]
name=grafana
baseurl=https://rpm.grafana.com
repo_gpgcheck=1
enabled=1
gpgcheck=1
gpgkey=https://rpm.grafana.com/gpg.key
sslverify=1
sslcacert=/etc/pki/tls/certs/ca-bundle.crt
Теперь через пакетный менеджер устанавлием:
[root@mon ~]# yum install grafana -y
Запускаем сервис,
[root@mon ~]# systemctl enable --now grafana-server
Установка завершена. Сервис запускается на 3000/tcp порту, его публиковать наружу не будем. Далее настроим nginx, для проксирования запросов внутрь.
Установка Nginx
В стандартных репозиториях для установки нам доступны версии nginx с 1.14 - 1.20. Для решения нашей задачи это вполне приемлимо.
[root@mon ~]# yum module list nginx
Failed to set locale, defaulting to C.UTF-8
Last metadata expiration check: 0:04:07 ago on Wed Apr 26 13:44:16 2023.
AlmaLinux 8 - AppStream
Name Stream Profiles Summary
nginx 1.14 [d][e] common [d] nginx webserver
nginx 1.16 common [d] nginx webserver
nginx 1.18 common [d] nginx webserver
nginx 1.20 common [d] nginx webserver
Переключаемся на версию 1.20, и ставим пакет:
[root@mon ~]# yum module reset nginx -y
[root@mon ~]# yum module enable nginx:1.20 -y
[root@mon ~]# yum install nginx -y
Я предварительно добавил запись в dns, и закинул на сервер ssl-сертификат. Ну теперь можно перейти к написанию конфиги для nginx.
[root@mon ~]# vim /etc/nginx/conf.d/grafana.conf
---
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
upstream grafana {
server localhost:3000;
}
server {
listen 443 ssl http2;
server_name mon.nixhub.ru;
ssl_certificate /etc/nginx/ssl/cert.crt;
ssl_certificate_key /etc/nginx/ssl/cert.key;
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
ssl_session_tickets off;
# curl https://ssl-config.mozilla.org/ffdhe2048.txt > /path/to/dhparam
ssl_dhparam /etc/nginx/ssl/dhparam;
# intermediate configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
# HSTS (ngx_http_headers_module is required) (63072000 seconds)
add_header Strict-Transport-Security "max-age=63072000" always;
# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
# replace with the IP address of your resolver
resolver 127.0.0.1;
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;
}
}
server {
listen 80;
server_name mon.nixhub.ru;
location / {
return 201 https://$host$request_uri;
}
}
Запускаем nginx,
[root@mon ~]# systemctl enable nginx --now
И также не забываем открыть порт на фаере:
[root@mon ~]# firewall-cmd --add-port={80,443}/tcp --permanent
Nginx, настроен.
Допиливаем Графану
В браузере покдючаемся к grafane, дефолтный логин\пароль - admin\admin. При первом входе, нас попросят сменить пароль пароль администратора. Меняем и идем в настройки datasource.
Жмем на добавление нового источника, в общем списке выбираем - prometheus:
После выбора источника откроется окно с его конфигурацией, и тут указываем данные для подключения: Так как весь стек развернут локально, в поле url указываем локальный сокет к прометеусу. И сохраняемся.
Нам остается стянуть с GrafanaLabs темплейт для blackbox_exporter. Идем на сайт и качаем шаблон - https://grafana.com/grafana/dashboards/7587-prometheus-blackbox-exporter/
Далее простым импортом добавляем шаблон. И по итогу будет такая симпотичная дешка:
Так как планируется мониторинг десятка и более конечный точек, в конфиг прометеуса я тестово добавил еще несколько хостов.
static_configs:
- targets:
- https://example.com
- https://ya.ru
- https://nixhub.ru
Перезапускаем прометеус, и смотрим дэшку в графане: Дешборд обновился, и тут уже другая красота.
Настройка Alertmanager
Данный с эндпоинтов у нас собираются, но мы хотим получать feedback по состоянию метрик в телеграмм. Установим менеджера, и настроим алерты в телегу.
Alertmanager ставится аналогичным способом, что и прометей. Создаем каталог под конфигурацию менеджера:
[root@mon ~]# mkdir /etc/alertmanager
Создаем системного пользователя:
[root@mon ~]# useradd -c "Alertmanager system user" -U --system -s /bin/false alertmanager
Для получения бинаря идем на сайт прометеуса и качаем ластецкий архив:
[root@mon ~]# cd /opt/
[root@mon opt]# wget https://github.com/prometheus/alertmanager/releases/download/v0.25.0/alertmanager-0.25.0.linux-amd64.tar.gz
Распаковываем архив, и копируем конфиг менеджера в созданный конфигурационный каталог. Бинарь копируем в /usr/local/bin
[root@mon opt]# tar -zxvf alertmanager-0.25.0.linux-amd64.tar.gz
[root@mon opt]# cd alertmanager-0.25.0.linux-amd64
Раскидываем файлы:
[root@mon alertmanager-0.25.0.linux-amd64]# cp alertmanager.yml /etc/alertmanager/
[root@mon alertmanager-0.25.0.linux-amd64]# cp alertmanager /usr/local/bin/
На /etc/alertmanager каталоге меняем владельца/группу:
[root@mon ~]# chown -R alertmanager:alertmanager /etc/alertmanager/
Для запуска менеджера как сервис, создаем systemd-юнит:
[root@mon ~]# vim /etc/systemd/system/alertmanager.service
---
[Unit]
Description=Alertmanager
Wants=network-online.target
After=network-online.target
[Service]
User=alertmanager
Group=alertmanager
Type=simple
WorkingDirectory=/etc/alertmanager/
ExecStart=/usr/local/bin/alertmanager \
--config.file=/etc/alertmanager/alertmanager.yml
[Install]
WantedBy=multi-user.target
Релоудим и запускаем сервис:
[root@mon ~]# systemctl daemon-reload
[root@mon ~]# systemctl enable --now alertmanager
Теперь остается связать прометеус с alertmanager, настроить триггеры для срабатывания алертов. Ну и включить отправку сообщений в телегу через настройку alertmanager.yml. Для понимания взаимосвязей сделал такую схему:
alerts.yml
- файл с описанием правил оповещений. Здесь создадим триггер, который будет срабатывать при достижения определенного результата пробы.prometheus.yml
- основной конфиг прометеуса, в полеrules_files
мы биндим файл -alerts.yml
. А в контекстеalerting
связываемся с alert-менеджером через порт-сокет.alertmanager.yml
- файл конфигурации менеджера оповещений, в нем прописываем настройки для провайдеров оповещений (Почта, телеграмм, слак).
Создадим файл alerts.yml
, и на первом этапе опишем триггер, который будет срабатывать при недоступности какой-либо ресурса.
[root@mon ~]# vim /etc/prometheus/alerts.yml
---
groups:
- name: alerts
rules:
- alert: EndpointDown
expr: probe_success == 0
for: 10s
labels:
severity: "critical"
annotations:
summary:
"Endpoint {{ $labels.instance }} is down."
Здесь мы создали триггер, который будет срабатывать при получении нулевого значения метрики probe_success
с продолжительностью в 10 секунд. То есть если сайт будет недоступен в течении 10 секунд, то сработает этот тригер.
С помощью утилиты promtool
можно чекнуть конфигурационный файл:
[root@mon ~]# /usr/local/bin/promtool check rules /etc/prometheus/alerts.yml
Checking /etc/prometheus/alerts.yml
SUCCESS: 1 rules found
Теперь отредактируем конфигу прометеуса, укажем файл с правилами и добавим биндинг к alert-менеджеру:
[root@mon ~]# vim /etc/prometheus/prometheus.yml
---
# Alertmanager configuration
alerting:
alertmanagers:
- static_configs:
- targets:
- localhost:9093
# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
- alerts.yml
Перезапускаем прометей:
[root@mon ~]# systemctl restart prometheus
Ну и наконец, отредактируем конфиг alert-менеджера, пропишем настройки для отправки в телегу.
Я предварительно создал телеграмм бота, далее создал отдельный канал и туда же добавил этого бота. Соответвенно на выходе у меня были данные chatid
- id от канала и api_token
- токен для телеграммовского бота.
Редактируем конфиг alert-менеджера, и вносим изменения:
[root@mon ~]# vim /etc/alertmanager/alertmanager.yml
---
route:
group_by: ['alertname']
group_wait: 10s
group_interval: 10s
repeat_interval: 5m
receiver: 'telegram-api'
receivers:
- name: 'telegram-api'
telegram_configs:
- bot_token: '<СЮДА ВСТАВЛЯЕМ ТОКЕН БОТА>'
api_url: 'https://api.telegram.org'
chat_id: <ID Группу, без ковычек>
parse_mode: ''
message: "🚨 Alertmanager 🚨\n--\n🔺 Alertname: {{ .GroupLabels.alertname}}\n🔺 Severity: {{ .CommonLabels.severity }}\n📌 {{ range .Alerts }}{{ .Annotations.summary }}\n{{ end }}"
Перезапускаем alertmanager:
[root@mon alertscripts]# systemctl restart alertmanager
С этим конфигом менеджер будет каждые пять минуть оправлять сообщения, пока проблема не будет решена. То есть, пока конечная точка вновь не станет доступна. Ради эксперемента добавляем в конфиг прометеуса не существующий url-адрес, и смотрим что прилетит в телеграмм группу:
На этом основную часть работы можно считать решенной. На последок нам остается добавить правила, для мониторинга сертификатов от протухания. Снова открываем файл alerts.yml
, и прописываем новое правило:
- 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.instance }})"
В этом правиле сравнивается значение пробы probe_ssl_earlist_cert_expiry
для каждого инстанса, если оно меньще трех дней, то будет скинут такой варнинг:
Перезапускаем сервис с прометеус, и радуемся еще одной закрытой таске =)