From b4f4493961bd5a3db38e0cd2544a99dafa6f9fb6 Mon Sep 17 00:00:00 2001 From: estorozhenko Date: Tue, 8 Sep 2026 06:01:01 +0000 Subject: [PATCH] =?UTF-8?q?Vinograd=20WAN=20(=D0=A0=D0=BE=D1=81=D1=82?= =?UTF-8?q?=D0=B5=D0=BB=D0=B5=D0=BA=D0=BE=D0=BC):=20ICMP-=D0=BC=D0=BE?= =?UTF-8?q?=D0=BD=D0=B8=D1=82=D0=BE=D1=80=D0=B8=D0=BD=D0=B3=20=D0=BA=D0=B0?= =?UTF-8?q?=D0=BD=D0=B0=D0=BB=D0=B0=20=D0=92=D0=B8=D0=BD=D0=BD=D1=8B=D0=B9?= =?UTF-8?q?=20=D0=B3=D0=BE=D1=80=D0=BE=D0=B4=20=E2=80=94=20=D1=88=D0=BB?= =?UTF-8?q?=D1=8E=D0=B7=2083.239.50.145=20+=20=D0=BE=D0=B1=D0=BE=D1=80?= =?UTF-8?q?=D1=83=D0=B4=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=2083.239.50.14?= =?UTF-8?q?6,=20scrape=2030s,=20RTT=20=D0=B3=D1=80=D0=B0=D1=84=D0=B8=D0=BA?= =?UTF-8?q?=D0=B8,=20=D0=B0=D0=BB=D0=B5=D1=80=D1=82=20VinogradRostelecomDo?= =?UTF-8?q?wn,=20=D0=B4=D0=B0=D1=88=D0=B1=D0=BE=D1=80=D0=B4=20Vinograd=20W?= =?UTF-8?q?AN?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- EXPERIENCE.md | 77 ++++++++++ README.md | 45 +++++- alerts.yml | 9 ++ blackbox.yml | 5 +- grafana/dashboards/vinograd-wan.json | 215 +++++++++++++++++++++++++++ prometheus.yml | 43 ++++++ 6 files changed, 391 insertions(+), 3 deletions(-) create mode 100644 grafana/dashboards/vinograd-wan.json diff --git a/EXPERIENCE.md b/EXPERIENCE.md index 3a14520..4adedec 100644 --- a/EXPERIENCE.md +++ b/EXPERIENCE.md @@ -4,6 +4,83 @@ > Ситуация: кластер Garage v2.1 (RF=3) на vps01 + bigbox + vps02, WireGuard 10.8.0.0/24. > Задача: вывести статус кластера в браузер (Grafana + Prometheus + Loki). +## Опыт: Vinograd WAN (Ростелеком) — ICMP-мониторинг внешнего канала (2026-09-08) + +> Ситуация: UptimeKuma алертил про 100% потерю пингов на шлюз 83.239.50.145 +> (канал «Винный город», РТК). Задача — мониторить ОБА адреса канала (шлюз + +> наше оборудование) в нашем стеке с графиками RTT каждые 30с. + +### 18. ICMP-пробы через blackbox-exporter — модуль `icmp` + +blackbox-exporter поддерживает ICMP-пробы (prober: icmp). Метрики: +- `probe_success` — 1/0 (успех пробы) +- `probe_icmp_duration_seconds{phase="rtt"}` — RTT в секундах +- `probe_icmp_reply_hop_limit` — TTL ответа + +Нюансы: +- В контейнере (host-network, root) ICMP работает без доп. настроек — проверил + `docker exec blackbox-exporter id` → root. В не-root окружении нужен + `setcap cap_net_raw+ep` или `net.ipv4.ping_group_range`. +- **Важно про YAML:** в `static_configs` таргеты — это список, `labels` относится + к списку целиком, а НЕ к каждому элементу отдельно. Ошибка синтаксиса ловится + `promtool check config`. + +### 19. Scrape job с интервалом 30s и relabel instance + +```yaml +- job_name: vinograd_wan + scrape_interval: 30s + metrics_path: /probe + params: + module: [icmp] + static_configs: + - targets: [83.239.50.145, 83.239.50.146] + relabel_configs: + # __address__ → instance: человекочитаемые имена для легенд Grafana + - source_labels: [__address__] + regex: '83\.239\.50\.145.*' + target_label: instance + replacement: vinograd-gw-83.239.50.145 + ... + # __address__ → реальный адрес blackbox (multi-target exporter pattern) + - target_label: __address__ + replacement: 127.0.0.1:9115 +``` + +- `scrape_interval: 30s` на уровне job — работает (проверено: точки каждые 30с). +- Regex с точками надо экранировать (`\.`), иначе 83.239.50.145 совпадёт с .146. +- relabel применяется по-порядку; сначала маппим instance, потом __address__ → blackbox. +- Проверка таргетов: `curl http://127.0.0.1:9090/api/v1/targets` → vinograd_wan 2 targets UP. + +### 20. Алерт на probe_success + +```yaml +- name: vinograd + rules: + - alert: VinogradRostelecomDown + expr: probe_success{job="vinograd_wan"} == 0 + for: 2m + labels: {severity: critical} +``` + +- `for: 2m` при scrape 30s ≈ 4 пробы подряд. `promtool check config` → 7 rules found. + +### 21. Grafana dashboard provisioning и ретеншн + +- Дашборд кладём в `grafana/dashboards/vinograd-wan.json` — provisioner + (updateIntervalSeconds: 30) сам импортирует в фолдере Garage; рестарт не нужен. + Проверка: в grafana.db появился dashboard с uid=vinograd-wan. +- **Ретеншн «неделя»:** retention в Prometheus глобальный (--storage.tsdb.retention.time=30d + в этом стеке). Для 7 дней ровно нужен отдельный инстанс — здесь оставили 30d + (перекрывает неделю с запасом). Не пытаться задать retention per-job — его нет. + +### 22. Наблюдение: шлюз РТК не пингуется, но оборудование пингуется + +- 83.239.50.146 (наше оборудование) — probe_success=1, RTT ~13ms. +- 83.239.50.145 (шлюз) — probe_success=0 (не отвечает на ICMP). Совпадает с + алертом UptimeKuma. Это реальная авария, а не ошибка конфига: blackbox + корректно видит недоступность шлюза. + ## Ключевые находки / грабли ### 1. Admin API Garage v2.1 слушает ОТДЕЛЬНЫЙ порт (`[admin] api_bind_addr`) diff --git a/README.md b/README.md index b8d0da9..7698563 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ -# Monitoring stack — Garage cluster (vps01 + bigbox + vps02) +# Monitoring stack — Garage cluster (vps01 + bigbox + vps02) + Vinograd WAN -Стек мониторинга для S3-кластера Garage (репликация RF=3, WireGuard 10.8.0.0/24). +Стек мониторинга для S3-кластера Garage (репликация RF=3, WireGuard 10.8.0.0/24) +и внешнего канала связи объекта «Винный город» (провайдер Ростелеком). Расположен на **bigbox** в `/opt/monitoring`. ## Архитектура @@ -116,11 +117,51 @@ curl -X POST -H "Authorization: token GITEA_TOK" \ | GarageNodeUnstable | `cluster_layout_node_connected == 0` (5м) | warning | | TProxyDown | `up{job="tproxy"} == 0` (2м) | critical | | TProxyBackendErrors| `increase(tproxy_backend_dial_failures_total[5m]) > 0` (10м) | warning | +| VinogradRostelecomDown | `probe_success{job="vinograd_wan"} == 0` (2м) | critical | Примечание: метрики Garage из admin API (:3903) НЕ имеют префикса `garage_` — это `api_s3_request_counter`, `block_resync_*`, `cluster_*`. Префикс `garage_` только у `garage_build_info`, `garage_local_disk_*`, `garage_replication_factor`. +## Vinograd WAN — внешний канал «Винный город» (Ростелеком) + +Объект «Винный город» (г. Геленджик, ул. Туристическая, 25), канал Ростелеком +(договор Бастион, Static IP). Адреса из «Реестра внешних каналов связи.ods» +(закладка «Винный город»): + +| Адрес | Роль | +|-------|------| +| 83.239.50.145 | Шлюз (gateway) — поднимается от РТК | +| 83.239.50.146 | Наше оборудование (CPE, Static IP, /30) | + +Мониторинг через **blackbox-exporter (ICMP-проба)** → Prometheus job `vinograd_wan`: + +- Интервал scrape: **30s** (графики скорости ответа каждые 30 секунд) +- Метрики: + - `probe_success{job="vinograd_wan"}` — доступность (1/0) + - `probe_icmp_duration_seconds{job="vinograd_wan",phase="rtt"}` — RTT, сек +- Лейблы `instance`: `vinograd-gw-83.239.50.145`, `vinograd-cpe-83.239.50.146` +- Алерт: **VinogradRostelecomDown** (critical, 2м подряд недоступен) +- Grafana: дашборд **Vinograd WAN** (RTT ms + availability), панели в фолдере Garage + +Retention: глобальный 30d (прометеевский TSDB) — данные хранятся минимум неделю, +что покрывает требование «хранить неделю» с запасом (жёсткий 7d для одного job +требовал бы отдельного инстанса Prometheus). + +Проверка вручную: +```bash +# ICMP-проба через blackbox (debug) +curl -s "http://127.0.0.1:9115/probe?target=83.239.50.146&module=icmp&debug=true" +# данные в Prometheus +curl -sG 'http://127.0.0.1:9090/api/v1/query' \ + --data-urlencode 'query=probe_success{job="vinograd_wan"}' +``` + +> Статус 2026-09-08: шлюз 83.239.50.145 НЕ отвечает на ICMP (probe_success=0, +> совпадает с алертом UptimeKuma 08:07 MSK). Оборудование 83.239.50.146 +> отвечает ~13ms. Алерт VinogradRostelecomDown в состоянии FIRE до восстановления +> канала — это корректное отражение реальной аварии. + ## tproxy-server (vps03) — метрики WEB Proxy (этап 6, РЕШЕНО ✅) tproxy-server (Telegram Desktop WEB Proxy) развёрнут на **vps03** (77.67.89.154), diff --git a/alerts.yml b/alerts.yml index 62530bc..e065d37 100644 --- a/alerts.yml +++ b/alerts.yml @@ -45,3 +45,12 @@ groups: severity: warning annotations: summary: tproxy-server backend dial failures (MTProxy unreachable) +- name: vinograd + rules: + - alert: VinogradRostelecomDown + expr: probe_success{job="vinograd_wan"} == 0 + for: 2m + labels: + severity: critical + annotations: + summary: Vinograd WAN (Ростелеком) {{ $labels.instance }} is down or unreachable diff --git a/blackbox.yml b/blackbox.yml index 96d593e..2fd67ec 100644 --- a/blackbox.yml +++ b/blackbox.yml @@ -4,4 +4,7 @@ modules: timeout: 5s http: valid_status_codes: [200] - follow_redirects: true \ No newline at end of file + follow_redirects: true + icmp: + prober: icmp + timeout: 5s \ No newline at end of file diff --git a/grafana/dashboards/vinograd-wan.json b/grafana/dashboards/vinograd-wan.json new file mode 100644 index 0000000..b4ce786 --- /dev/null +++ b/grafana/dashboards/vinograd-wan.json @@ -0,0 +1,215 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "__grafana__" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "style" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": null, + "links": [], + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "Prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 2, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Prometheus" + }, + "expr": "probe_success{job=\"vinograd_wan\"}", + "legendFormat": "{{ instance }}", + "refId": "A" + } + ], + "title": "Vinograd WAN availability", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "Prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "ms", + "axisPlacement": "auto", + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 3, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "Prometheus" + }, + "expr": "probe_icmp_duration_seconds{job=\"vinograd_wan\",phase=\"rtt\"} * 1000", + "legendFormat": "{{ instance }}", + "refId": "A" + } + ], + "title": "Vinograd WAN RTT (ms)", + "type": "timeseries" + } + ], + "refresh": "30s", + "schemaVersion": 39, + "tags": [ + "vinograd", + "wan", + "rostelecom" + ], + "templating": { + "list": [] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "Europe/Moscow", + "title": "Vinograd WAN", + "uid": "vinograd-wan", + "version": 1, + "weekStart": "" +} \ No newline at end of file diff --git a/prometheus.yml b/prometheus.yml index b4af32d..8a203f0 100644 --- a/prometheus.yml +++ b/prometheus.yml @@ -96,6 +96,18 @@ scrape_configs: static_configs: - targets: - localhost:9090 +- job_name: gotosocial + metrics_path: /metrics + scheme: http + static_configs: + - targets: + - 127.0.0.1:9464 + labels: + service: gotosocial + host: bigbox + relabel_configs: + - target_label: instance + replacement: bigbox:9464 - job_name: tproxy static_configs: - targets: @@ -108,3 +120,34 @@ scrape_configs: replacement: vps03:8081 - target_label: host replacement: vps03 +- job_name: vinograd_wan + scrape_interval: 30s + metrics_path: /probe + params: + module: + - icmp + static_configs: + - targets: + - 83.239.50.145 + - 83.239.50.146 + labels: + channel: vinograd-rtk + relabel_configs: + - source_labels: + - __address__ + regex: '83\.239\.50\.145.*' + target_label: instance + replacement: vinograd-gw-83.239.50.145 + - source_labels: + - __address__ + regex: '83\.239\.50\.146.*' + target_label: instance + replacement: vinograd-cpe-83.239.50.146 + - source_labels: + - __address__ + target_label: __param_target + - source_labels: + - __param_target + target_label: target + - target_label: __address__ + replacement: 127.0.0.1:9115