mirror of
https://gitverse.ru/kpa39l/monitoring.git
synced 2026-09-29 01:50:07 +00:00
feat(openspec): vesti-alerts — 6 алертов на компоненты VESTI (web/publisher/tunnel/db/stale); OpenSpec change
This commit is contained in:
@@ -252,6 +252,44 @@ grafana.nixg.ru {
|
||||
- В логах caddy много ошибок renew для старых доменов — они имеют
|
||||
уже выпущенные сертификаты в caddy_data, работает всё.
|
||||
|
||||
## Опыт: VESTI — textfile-метрики + встроенный Prometheus Alerting (2026-09-13)
|
||||
|
||||
> Ситуация: добавлен дашборд и алерты на компоненты /opt/vesti. Проект
|
||||
> управляется через OpenSpec: все изменения — только через openspec/change.
|
||||
|
||||
### 22. Textfile-коллектор node-exporter для метрик сервиса
|
||||
|
||||
node-exporter умеет отдавать произвольные метрики из файлов каталога
|
||||
(`--collector.textfile.directory=...` ← `ARGS` в /etc/default/prometheus-node-exporter).
|
||||
Скрипт раз в минуту пишет файл в Prometheus-формате (1 метрика = 1 строка
|
||||
`name{labels} value`), node-exporter отдаёт их в /metrics — и Prometheus
|
||||
тащит их обычным job'ом `node` (тот же 9100). Для сервиса достаточно:
|
||||
`/opt/vesti/scripts/vesti-metrics.sh` → `/var/lib/node_exporter/textfile_collector/vesti.prom`.
|
||||
|
||||
Грабля: каталог textfile принадлежит пользователю `prometheus`, скрипт от
|
||||
root должен делать `chown prometheus:prometheus` (иначе файл появится, но
|
||||
node-exporter его не прочитает — права!). Запуск: cron.d (root) — каждую минуту.
|
||||
|
||||
### 23. Prometheus-алерты: файл alerts.yml + `/api/v1/rules`
|
||||
|
||||
В этом стеке алерты — НЕ Grafana, а встроенный механизм Prometheus:
|
||||
`prometheus.yml` → `rule_files: /etc/prometheus/alerts.yml` (группы/правила в
|
||||
YAML). Правила видны в `http://127.0.0.1:9090/api/v1/rules` (JSON: groups,
|
||||
state, query). Перечитываются ТОЛЬКО рестартом прометеуса
|
||||
(`docker restart prometheus`), НЕ автоматически.
|
||||
|
||||
Грабля: `promtool check config /etc/prometheus/prometheus.yml` считает
|
||||
alerts.yml правило-файлом: «FAILED: field groups not found» при прямом
|
||||
проверке alerts.yml — это НОРМАЛЬНО (это не самостоятельный конфиг;
|
||||
проверять через рrometheus.yml, который находит 13 rules).
|
||||
|
||||
### 24. OpenSpec для /opt/monitoring
|
||||
|
||||
Все изменения проекта — ТОЛЬКО через `openspec/change/` (proposal/design/tasks/
|
||||
specs/). Формат spec: `## ADDED Requirements` + `### Requirement: X` +
|
||||
`#### Scenario:` (иначе validate ругается). После внесения: `openspec validate`,
|
||||
применить, `openspec archive --yes` + обновить STATUS/README/WALKTHROUGH.
|
||||
|
||||
## Опыт: дашборд Grafana пустой (NO DATA) — 3 причины подряд (2026-09-02)
|
||||
|
||||
> Дата: 2026-09-02. Ситуация: после этапа 6 (tproxy) пользователь сообщил,
|
||||
|
||||
@@ -226,3 +226,50 @@ admin-эндпоинты на loopback :8081: `/healthz`, `/readyz`, `/metrics`
|
||||
Порядок работы: правки коммитятся и пушутся в gitverse (источник), gitea
|
||||
подтягивает их mirror'ом (каждые 8ч или вручную mirror-sync). Если bigbox
|
||||
сломается — репозиторий остаётся в облаке gitverse.
|
||||
|
||||
## VESTI (2026-09-13)
|
||||
|
||||
Проект /opt/vesti: web-интерфейс (:8400, systemd), publisher-контейнер
|
||||
(docker `vesti-publisher`, :8410/healthz), SOCKS5-туннель Telegram (:1080),
|
||||
SQLite БД (vesti.db).
|
||||
|
||||
### Метрики (textfile-коллектор node-exporter, job `node`, label `component="vesti"`)
|
||||
|
||||
Скрипт `/opt/vesti/scripts/vesti-metrics.sh` (запуск: cron.d `vesti-metrics`,
|
||||
root, каждую минуту; альтернативно systemd-таймер `vesti-metrics.timer`)
|
||||
пишет `/var/lib/node_exporter/textfile_collector/vesti.prom`. node-exporter
|
||||
на bigbox: `ARGS="--web.listen-address=10.8.0.2:9100 --collector.textfile.directory=/var/lib/node_exporter/textfile_collector"`.
|
||||
|
||||
| Метрика | Смысл |
|
||||
|---|---|
|
||||
| vesti_web_up | web :8400 (systemd) |
|
||||
| vesti_publisher_health | publisher :8410 /healthz |
|
||||
| vesti_publisher_docker | контейнер publisher (Up) |
|
||||
| vesti_telegram_tunnel | SOCKS5-туннель :1080 |
|
||||
| vesti_web_systemd | systemd-юнит web |
|
||||
| vesti_publisher_bot / _proxy / _channels | детали publisher |
|
||||
| vesti_db_ok | SQLite vesti.db доступна |
|
||||
| vesti_db_posts_total / _new_total / _published_total | счётчики БД |
|
||||
| vesti_db_last_run_ts | Unix-ts последнего рan краулера |
|
||||
|
||||
### Дашборд
|
||||
|
||||
`grafana/dashboards/vesti/vesti.json` (uid `vesti`, папка **vesti**), 18 панелей.
|
||||
Провайдер `vesti-dashboards` в `grafana/provisioning/dashboards/dashboards.yml`.
|
||||
Проверка импорта: `sudo docker cp grafana:/var/lib/grafana/grafana.db /tmp/gf.db`
|
||||
+ `SELECT uid,title FROM dashboard WHERE uid='vesti'`.
|
||||
|
||||
### Алерты (группа `vesti` в alerts.yml)
|
||||
|
||||
| Алерт | Выражение | Удержание | Severity |
|
||||
|---|---|---|---|
|
||||
| VestiWebDown | `vesti_web_up{component="vesti"} == 0` | 2m | critical |
|
||||
| VestiPublisherDown | `vesti_publisher_health{component="vesti"} == 0` | 2m | critical |
|
||||
| VestiPublisherContainerDown | `vesti_publisher_docker{component="vesti"} == 0` | 2m | critical |
|
||||
| VestiTunnelDown | `vesti_telegram_tunnel{component="vesti"} == 0` | 2m | critical |
|
||||
| VestiDbDown | `vesti_db_ok{component="vesti"} == 0` | 2m | critical |
|
||||
| VestiDbStale | `time() - vesti_db_last_run_ts{component="vesti"} > 1800` | 5m | warning |
|
||||
|
||||
Реализовано через встроенный Prometheus Alerting (`rule_files` в prometheus.yml
|
||||
→ alerts.yml; правила видны в `/api/v1/rules`). Перечитывается рестартом
|
||||
прометеуса (`docker restart prometheus`).
|
||||
+44
@@ -54,3 +54,47 @@ groups:
|
||||
severity: critical
|
||||
annotations:
|
||||
summary: Vinograd WAN (Ростелеком) {{ $labels.instance }} is down or unreachable
|
||||
- name: vesti
|
||||
rules:
|
||||
- alert: VestiWebDown
|
||||
expr: vesti_web_up{component="vesti"} == 0
|
||||
for: 2m
|
||||
labels:
|
||||
severity: critical
|
||||
annotations:
|
||||
summary: VESTI web (:8400, systemd) is down
|
||||
- alert: VestiPublisherDown
|
||||
expr: vesti_publisher_health{component="vesti"} == 0
|
||||
for: 2m
|
||||
labels:
|
||||
severity: critical
|
||||
annotations:
|
||||
summary: VESTI publisher (:8410) health check failed
|
||||
- alert: VestiPublisherContainerDown
|
||||
expr: vesti_publisher_docker{component="vesti"} == 0
|
||||
for: 2m
|
||||
labels:
|
||||
severity: critical
|
||||
annotations:
|
||||
summary: VESTI publisher Docker container is not Up
|
||||
- alert: VestiTunnelDown
|
||||
expr: vesti_telegram_tunnel{component="vesti"} == 0
|
||||
for: 2m
|
||||
labels:
|
||||
severity: critical
|
||||
annotations:
|
||||
summary: VESTI Telegram SOCKS5 tunnel (:1080) is down
|
||||
- alert: VestiDbDown
|
||||
expr: vesti_db_ok{component="vesti"} == 0
|
||||
for: 2m
|
||||
labels:
|
||||
severity: critical
|
||||
annotations:
|
||||
summary: VESTI SQLite database vesti.db is unavailable
|
||||
- alert: VestiDbStale
|
||||
expr: time() - vesti_db_last_run_ts{component="vesti"} > 1800
|
||||
for: 5m
|
||||
labels:
|
||||
severity: warning
|
||||
annotations:
|
||||
summary: VESTI crawler did not run for more than 30 minutes
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
# Design
|
||||
|
||||
## Механизм алертов
|
||||
|
||||
В стеке /opt/monitoring алерты реализованы **Prometheus Alerting rules** (prometheus.yml
|
||||
`rule_files: /etc/prometheus/alerts.yml`, Prometheus 3.1+ встроенный алертинг с мульти-секционной
|
||||
группировкой `groups:`/`rules:`). Формат rules (алерты на базе PromQL-выражений с `for` = время
|
||||
удержания условия, `labels.severity`, `annotations.summary`). Доставка уведомлений — согласно
|
||||
существующей конфигурации (webhook/канал, настроенный в Prometheus или в той же alerts.yml
|
||||
внешним получателем — проверить фактический механизм доставки в стеке; в референсах скилла
|
||||
указано, что уведомления приходят в чат).
|
||||
|
||||
## Метрики VESTI (textfile-коллектор, job `node`, label `component="vesti"`)
|
||||
|
||||
| Метрика | Смысл | Алерт |
|
||||
|---|---|---|
|
||||
| vesti_web_up | web :8400 (systemd) | ==0 → critical |
|
||||
| vesti_publisher_health | publisher :8410 /healthz | ==0 → critical |
|
||||
| vesti_publisher_docker | контейнер publisher (docker ps) | ==0 → critical |
|
||||
| vesti_telegram_tunnel | SOCKS5-туннель :1080 | ==0 → critical |
|
||||
| vesti_db_ok | SQLite vesti.db доступна | ==0 → critical |
|
||||
| vesti_db_last_run_ts | Unix-ts последнего рan краулера | time()-ts >1800 → warning |
|
||||
|
||||
## Формат rules (из alerts.yml)
|
||||
|
||||
```yaml
|
||||
groups:
|
||||
- name: vesti
|
||||
rules:
|
||||
- alert: VestiWebDown
|
||||
expr: vesti_web_up{component="vesti"} == 0
|
||||
for: 2m
|
||||
labels:
|
||||
severity: critical
|
||||
annotations:
|
||||
summary: VESTI web (:8400) is down
|
||||
```
|
||||
|
||||
Время реакции: `for: 2m` — алерт срабатывает после 2 минут непрерывного условия
|
||||
(метрики обновляются раз в минуту скриптом vesti-metrics.sh → 2-3 пробы подряд).
|
||||
|
||||
## Верификация
|
||||
|
||||
1. `docker exec prometheus promtool check config /etc/prometheus/prometheus.yml` → OK
|
||||
(проверяет и rule_files).
|
||||
2. `docker compose restart prometheus` (перечитывает alerts.yml).
|
||||
3. Запрос в Prometheus API: значения метрик vesti_* присутствуют.
|
||||
4. Проверка алертов: имитация (временно выставить метрику в 0, убедиться что алерт firing,
|
||||
вернуть обратно) — или проверка через Prometheus /api/v1/rules/дубликат.
|
||||
5. Обновить README.md + EXPERIENCE.md, openspec validate + archive.
|
||||
|
||||
## Риски
|
||||
|
||||
- При `for: 2m` и интервале скрипта 1 мин алерт может срабатывать с задержкой до 3 мин
|
||||
(приемлемо для внутреннего сервиса).
|
||||
- Метрики пишутся только при успешном выполнении скрипта; если textfile-файл пропадёт
|
||||
(сломан скрипт) — метрики исчезнут и алерт по `==0` не сработает. Для этого есть
|
||||
`VestiDbStale` (time() - ts) — он тоже покроет случай пропадания данных? Нет: если файл
|
||||
пропал, ts не обновится → last_run_ts останется старым → VestiDbStale сработает.
|
||||
Дополнительно можно добавить expr на отсутствие данных (deadman), но это выходит за рамки
|
||||
текущего change — зафиксировать в EXPERIENCE.md как известное ограничение.
|
||||
@@ -0,0 +1,30 @@
|
||||
# Proposal: vesti-alerts
|
||||
|
||||
## Why
|
||||
|
||||
Проект /opt/vesti (веб :8400 + publisher-контейнер :8410 + SOCKS5-туннель :1080 + SQLite БД)
|
||||
получил дашборд VESTI в Grafana (2026-09-13), но **алертов на падение компонентов нет**:
|
||||
при недоступности web/publisher/туннеля/БД никто не узнает в реальном времени (только постфактум
|
||||
на дашборде). Нужны алерты в существующем механизме мониторинга (Prometheus rule_files → alerts.yml)
|
||||
на все компоненты vesti, с уведомлением (webhook/настроенный канал).
|
||||
|
||||
## What Changes
|
||||
|
||||
- В `/opt/monitoring/alerts.yml` добавляется группа `vesti` с алертами:
|
||||
- `VestiWebDown` — `vesti_web_up{component="vesti"} == 0`, for 2m, severity: critical
|
||||
- `VestiPublisherDown` — `vesti_publisher_health{component="vesti"} == 0`, for 2m, severity: critical
|
||||
- `VestiPublisherContainerDown` — `vesti_publisher_docker{component="vesti"} == 0`, for 2m, severity: critical
|
||||
- `VestiTunnelDown` — `vesti_telegram_tunnel{component="vesti"} == 0`, for 2m, severity: critical
|
||||
- `VestiDbDown` — `vesti_db_ok{component="vesti"} == 0`, for 2m, severity: critical
|
||||
- `VestiDbStale` — `time() - vesti_db_last_run_ts{component="vesti"} > 1800`, for 5m, severity: warning
|
||||
(краулер не работал >30 мин)
|
||||
- Все алерты аннотируются summary с именем компонента.
|
||||
- Верификация: `promtool check config` + запрос фактических значений в Prometheus API.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
- `vesti-alerts`: алерты на компоненты VESTI (web, publisher, docker, tunnel, db, краулер staleness).
|
||||
|
||||
### Modified Capabilities
|
||||
- `monitoring-stack` (alerts.yml) — добавлена группа `vesti`.
|
||||
@@ -0,0 +1,99 @@
|
||||
# vesti-alerts
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: VestiWebDown
|
||||
|
||||
Алерт на недоступность web-интерфейса VESTI (:8400, systemd-юнит).
|
||||
|
||||
#### Scenario: web не отвечает
|
||||
|
||||
- Given метрика `vesti_web_up{component="vesti"}` = 0
|
||||
- When условие держится 2 минуты
|
||||
- Then алерт `VestiWebDown` переходит в Firing (severity critical)
|
||||
|
||||
#### Scenario: web восстановился
|
||||
|
||||
- Given метрика `vesti_web_up{component="vesti"}` = 1
|
||||
- When алерт в Firing
|
||||
- Then алерт закрывается автоматически
|
||||
|
||||
### Requirement: VestiPublisherDown
|
||||
|
||||
Алерт на недоступность publisher-сервиса VESTI (:8410, /healthz).
|
||||
|
||||
#### Scenario: publisher не отвечает
|
||||
|
||||
- Given метрика `vesti_publisher_health{component="vesti"}` = 0
|
||||
- When условие держится 2 минуты
|
||||
- Then алерт `VestiPublisherDown` переходит в Firing (severity critical)
|
||||
|
||||
#### Scenario: publisher восстановился
|
||||
|
||||
- Given метрика `vesti_publisher_health{component="vesti"}` = 1
|
||||
- When алерт в Firing
|
||||
- Then алерт закрывается автоматически
|
||||
|
||||
### Requirement: VestiPublisherContainerDown
|
||||
|
||||
Алерт на остановку Docker-контейнера publisher.
|
||||
|
||||
#### Scenario: контейнер publisher не в статусе Up
|
||||
|
||||
- Given метрика `vesti_publisher_docker{component="vesti"}` = 0
|
||||
- When условие держится 2 минуты
|
||||
- Then алерт `VestiPublisherContainerDown` переходит в Firing (severity critical)
|
||||
|
||||
#### Scenario: контейнер publisher снова Up
|
||||
|
||||
- Given метрика `vesti_publisher_docker{component="vesti"}` = 1
|
||||
- When алерт в Firing
|
||||
- Then алерт закрывается автоматически
|
||||
|
||||
### Requirement: VestiTunnelDown
|
||||
|
||||
Алерт на недоступность SOCKS5-туннеля Telegram (:1080).
|
||||
|
||||
#### Scenario: туннель недоступен
|
||||
|
||||
- Given метрика `vesti_telegram_tunnel{component="vesti"}` = 0
|
||||
- When условие держится 2 минуты
|
||||
- Then алерт `VestiTunnelDown` переходит в Firing (severity critical)
|
||||
|
||||
#### Scenario: туннель восстановился
|
||||
|
||||
- Given метрика `vesti_telegram_tunnel{component="vesti"}` = 1
|
||||
- When алерт в Firing
|
||||
- Then алерт закрывается автоматически
|
||||
|
||||
### Requirement: VestiDbDown
|
||||
|
||||
Алерт на недоступность SQLite-базы vesti.db.
|
||||
|
||||
#### Scenario: БД недоступна
|
||||
|
||||
- Given метрика `vesti_db_ok{component="vesti"}` = 0
|
||||
- When условие держится 2 минуты
|
||||
- Then алерт `VestiDbDown` переходит в Firing (severity critical)
|
||||
|
||||
#### Scenario: БД восстановилась
|
||||
|
||||
- Given метрика `vesti_db_ok{component="vesti"}` = 1
|
||||
- When алерт в Firing
|
||||
- Then алерт закрывается автоматически
|
||||
|
||||
### Requirement: VestiDbStale
|
||||
|
||||
Алерт на устаревание данных краулера (не запускался >30 минут).
|
||||
|
||||
#### Scenario: краулер не запускался более 30 минут
|
||||
|
||||
- Given метрика `vesti_db_last_run_ts{component="vesti"}` = T
|
||||
- When `time() - T` > 1800 секунд и условие держится 5 минут
|
||||
- Then алерт `VestiDbStale` переходит в Firing (severity warning)
|
||||
|
||||
#### Scenario: краулер снова запустился
|
||||
|
||||
- Given метрика `vesti_db_last_run_ts{component="vesti"}` обновлена (time() - ts < 1800)
|
||||
- When алерт в Firing
|
||||
- Then алерт закрывается автоматически
|
||||
@@ -0,0 +1,22 @@
|
||||
# Tasks
|
||||
|
||||
## 1. Алерты в alerts.yml
|
||||
- [x] 1.1 В `/opt/monitoring/alerts.yml` добавить группу `vesti`:
|
||||
- VestiWebDown (vesti_web_up == 0, for 2m, critical)
|
||||
- VestiPublisherDown (vesti_publisher_health == 0, for 2m, critical)
|
||||
- VestiPublisherContainerDown (vesti_publisher_docker == 0, for 2m, critical)
|
||||
- VestiTunnelDown (vesti_telegram_tunnel == 0, for 2m, critical)
|
||||
- VestiDbDown (vesti_db_ok == 0, for 2m, critical)
|
||||
- VestiDbStale (time() - vesti_db_last_run_ts > 1800, for 5m, warning)
|
||||
- [x] 1.2 Проверка: `docker exec prometheus promtool check config /etc/prometheus/prometheus.yml` → OK (13 rules)
|
||||
- [x] 1.3 Рестарт: `docker restart prometheus`
|
||||
- [x] 1.4 Проверка: группа vesti в /api/v1/rules, 6 правил, state=inactive (норма)
|
||||
|
||||
## 2. Документация
|
||||
- [x] 2.1 Обновить `/opt/monitoring/README.md` (секция VESTI: алерты, метрики)
|
||||
- [x] 2.2 Добавить запись в `/opt/monitoring/EXPERIENCE.md` (22-24: textfile, alerting, OpenSpec)
|
||||
|
||||
## 3. Git и OpenSpec
|
||||
- [ ] 3.1 `git add` (поимённо) + commit + push в gitverse (истина), gitea подтянет mirror
|
||||
- [ ] 3.2 `openspec validate` + `openspec archive --yes`
|
||||
- [ ] 3.3 Обновить STATUS.md/WALKTHROUGH.md
|
||||
Reference in New Issue
Block a user