32 KiB
Опыт эксплуатации: мониторинг Garage v2.1 через Prometheus
Дата: 2026-08-30 Ситуация: кластер 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
- 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
- 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 корректно видит недоступность шлюза.
23. Read-only пользователь Grafana: provisioning НЕ работает (OSS), только UI (2026-09-08)
Задача: дать сотруднику IT Винограда read-only доступ к дашбордам
(it@vinogorod.ru, роль Viewer). Попытки автоматизировать — провалились:
- Файловое provisioning пользователей (
grafana/provisioning/access-control/users.yml) в Grafana 11 OSS не обрабатывается: в логах старта только dashboards/datasources/alerting/plugins; access-control — фича Enterprise/Cloud (security.provisioning). Файл молча игнорируется, даже с валидным YAML. - API create:
POST /api/users→ 404 (в OSS недоступно).POST /api/login(JSON) → 401 даже при верном пароле; а Basic auth работает (curl -u estorozhenko:пароль /api/user→ 200). - Итог: пользователя можно создать только в UI (Administration → Users → New user, роль Viewer). Пароль задаётся при создании.
Проверка после создания:
curl -s -u 'it@vinogorod.ru:1qazXSW2' http://127.0.0.1:3001/api/user # → 200
curl -s -u 'estorozhenko:ПАРОЛЬ' http://127.0.0.1:3001/api/orgs/1/users # role=Viewer
curl -s -u 'it@vinogorod.ru:1qazXSW2' http://127.0.0.1:3001/api/users # → 403 (read-only)
24. Ошибка "Datasource grafana was not found" при открытии дашборда (2026-09-08)
Симптом: на https://grafana.nixg.ru/d/vinograd-wan/vinograd-wan выскакивало
окно "Failed to retrieve datasource / Datasource grafana was not found".
Панели при этом в порядке (Prometheus uid есть), а секция annotations
в JSON дашборда ссылалась на встроенный датасорс:
"annotations": { "list": [ { "builtIn": 1,
"datasource": {"type": "grafana", "uid": "__grafana__"}, ... } ] }
__grafana__— встроенный datasource Grafana (аннотации/алерты). В нашей БДdata_sourceего НЕТ (только Prometheus и Loki) → Grafana 11 OSS не может его найти и показывает ошибку. Панели не используют аннотации — секция добавляется в JSON автоматически при создании (шаблон), но в файле она бесполезна.- Фикс: очистить
annotations.listв файле дашборда:Провайдер дашбордов перечитывает файл каждые 30с (рестарт не нужен), в БД появляется version 2 сjq '.annotations.list = []' grafana/dashboards/vinograd-wan.json > /tmp/vw.json \ && mv /tmp/vw.json grafana/dashboards/vinograd-wan.json"list": []— ошибка исчезает. - Эталон: рабочий
garage-cluster.jsonвсегда имеет"annotations": {"list": []}. - Проверка из БД:
docker cp grafana:/var/lib/grafana/grafana.db /tmp/gf.db→SELECT data FROM dashboard WHERE uid='vinograd-wan'→__grafana__отсутствует.
Ключевые находки / грабли
1. Admin API Garage v2.1 слушает ОТДЕЛЬНЫЙ порт ([admin] api_bind_addr)
Самое важное. Если api_bind_addr НЕ задан в [admin], Garage слушает admin
(включая /metrics) на том же порту, что S3 API (3900). В этом случае
Authorization: Bearer TOKEN к /metrics на 3900 отвечает
400 Bad request: Unsupported authorization method — авторизация S3 не понимает
Bearer, а admin-роутер не подключён.
Решение: добавить в [admin] отдельный адрес:
[admin]
api_bind_addr = "10.8.0.2:3903" # свой WG-IP на каждой ноде
metrics_token = "..."
admin_token = "..."
После рестарта ноды /metrics и /health доступны на :3903.
2. metrics_token НЕ обязателен
Если metrics_token не задан — /metrics доступен без авторизации.
Если задан — используется как обычный Bearer token:
curl -H "Authorization: Bearer TOKEN" http://node:3903/metrics
(совпадает с синтаксисом admin_token; для метрик достаточно metrics_token).
3. Docker-образ dxflrs/garage:v2.1.0 — scratch без shell
- Нет
/bin/sh, нетls,docker exec garage ls— не работает. - CLI-бинарь лежит по пути
/garageвнутри образа, а НЕ в PATH. - Поэтому проверка статуса через docker run:
docker run --rm \
-v /opt/garage/garage.toml:/etc/garage.toml:ro \
-v /opt/garage/meta:/var/lib/garage/meta \
--entrypoint /garage dxflrs/garage:v2.1.0 status
(без монтирования meta будет ошибка "Unable to read node key").
4. Перезапуск нод кластера — безопасно, но по очереди
docker compose restart garage на всех трёх нодах прошёл без потери кворума
и без пересборки layout — кластер остался HEALTHY (layout version 1 сохранился).
Порядок: внешние (vps02, vps01) → bigbox. Пауза ~8с между рестартами.
5. UFW на vps01 режет новые порты
Порт 3903 на vps01 был закрыт UFW (в отличие от 3901, открытого для Anywhere). Пришлось:
sudo ufw allow from 10.8.0.0/24 to any port 3903 proto tcp comment "garage admin metrics"
Аналогично пришлось открыть 9100 (node-exporter):
sudo ufw allow from 10.8.0.0/24 to any port 9100 proto tcp
На vps02 файрвол — nftables с policy ACCEPT, порт не блокировался.
6. Конфиг garage.toml на vps01/vps02 принадлежит root
Правка через SSH требует sudo (python не может писать напрямую):
ssh vps01 'sudo sed -i "s|^\[admin\]$|[admin]\napi_bind_addr = \"10.8.0.1:3903\"|" /opt/garage/garage.toml'
7. Docker bridge-сеть НЕ видит WireGuard-интерфейс хоста
Самое важное при разворачивании стека мониторинга: контейнеры в дефолтной bridge-сети (docker compose networks) не имеют доступа к WG-подсети 10.8.0.0/24 хоста. Prometheus не мог достать 10.8.0.x:3903, blackbox — тем более.
Решение: prometheus и blackbox-exporter запущены с network_mode: host.
Они видят и WG-интерфейс, и друг друга через 127.0.0.1. Grafana, Loki, Promtail
остались в bridge-сети (им WG не нужен).
8. /health Garage возвращает ТЕКСТ, а не метрику
curl http://node:3903/health → Garage is fully operational (текст, HTTP 200).
Нельзя использовать как metrics-таргет: Prometheus пытается распарсить текст
как float → strconv.ParseFloat: parsing "is".
Решение: health-проверка через blackbox-exporter (module http_2xx,
probe_success). В prometheus.yml job garage_health с params: module: [http_2xx],
relabel __address__ → 127.0.0.1:9115.
9. node-exporter — ставится apt'ом
Ubuntu (bigbox): prometheus-node-exporter 1.7.0; Debian 13 (vps01/vps02):
1.9.0. Работает сразу как systemd-сервис на :9100 (*:9100, все интерфейсы — WG
виден). На vps01 дополнительно открыть 9100 в ufw (см. п.5).
10. Права на volume-каталоги мониторинга
Контейнеры запускаются от не-root UID, а каталоги создавались от root:
- prometheus: UID 65534 (nobody) →
chown 65534:65534 prometheus-data - loki: UID 10001 →
chown 10001:10001 loki-data - grafana: UID 472 →
chown 472:472 grafana-data
Иначе: prometheus падает с Unable to create mmap-ed active query log,
loki — mkdir /loki/rules: permission denied.
11. Caddy на vps02 — docker, host network, конфиг /opt/caddy/Caddyfile
Grafana опубликована как grafana.nixg.ru (DNS → 87.242.100.206 = vps02):
grafana.nixg.ru {
reverse_proxy 10.8.0.2:3001
}
- Caddy в docker (
network_mode: host), конфиг смонтирован из /opt/caddy/Caddyfile. - Перезагрузка:
docker exec caddy caddy reload --config /etc/caddy/Caddyfile - Сертификат Let's Encrypt выпускается автоматически (http-01), но первые ~30с после reload соединение может падать — это нормально.
- В логах 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) пользователь сообщил, что дашборд Garage Cluster в Grafana полностью пустой (NO DATA).
12. NO DATA #1: у datasource не задан uid — Grafana генерит случайный
В grafana/provisioning/datasources/datasources.yml у Prometheus-датасорса
НЕ был задан uid. Grafana при провиженинге присваивает датасорсу случайный
UID (в БД видно для Loki: P8E80F9AEF21F6940), а все панели дашборда
ссылались на "uid": "Prometheus". Панели искали датасорс с таким uid — не
находили → NO DATA.
Решение: в datasources.yml добавить датасорсу явный uid: Prometheus
(совпадение 1-в-1 с uid в панелях). Дашборды провиженятся каждые 30с,
а datasources — только при старте Grafana → после правки docker compose restart grafana. Проверка из БД (docker cp grafana:/var/lib/grafana/grafana.db):
SELECT name, uid, url FROM data_source → uid стал Prometheus.
13. NO DATA #2: Prometheus на host-сети, а datasource URL http://prometheus:9090
Prometheus и blackbox запущены с network_mode: host (нужно для WG 10.8.0.0/24),
а Grafana — в bridge-сети. Внутри сети Grafana имя prometheus не
резолвится (проверено docker exec grafana getent hosts prometheus →
NO_RESOLVE), поэтому URL http://prometheus:9090 недостижим → панели без
данных. Loki в той же bridge-сети — резолвится нормально.
Решение: datasource URL заменить на http://172.28.0.1:9090 — IP хоста
со стороны bridge-сети Grafana (шлюз сети = адрес хоста). Определяется так:
docker inspect grafana --format '{{range .NetworkSettings.Networks}}{{.Gateway}} {{end}}'
# → 172.28.0.1
Проверено из контейнера: wget http://172.28.0.1:9090/-/healthy → OK.
ВАЖНО: шлюз bridge-сети docker стабилен (подсеть фиксированная),
но если пересоздать сеть — IP может смениться.
14. NO DATA #3 (частично): панели ссылались на НЕСУЩЕСТВУЮЩИЕ метрики
После починки datasource tproxy-панели ожили, а garage-панели (blocks, RPC node health, S3 req/sec) остались пустыми. Причина: панели были написаны под НЕСУЩЕСТВУЮЩИЕ имена метрик, которых в Prometheus нет:
garage_block_count— в реальностиblock_resync_queue_length/block_resync_errored_blocksgarage_rpc_node_health_is_up— в реальностиcluster_layout_node_connectedgarage_api_s3_request_counter— в реальностиapi_s3_request_counter
Метрики Garage из admin API (10.8.0.x:3903) не имеют префикса garage_:
api_s3_request_counter, api_s3_request_duration_*, block_resync_*,
cluster_* (connected_nodes, healthy, partitions_all_ok, layout_node_connected),
table_*, rpc_*. Префикс garage_ есть только у garage_build_info,
garage_local_disk_avail/total, garage_replication_factor.
Проверка реальных метрик: curl 'http://127.0.0.1:9090/api/v1/label/__name__/values'
и фильтр по job=garage. Панели переписаны на реальные метрики:
- Garage blocks (resync):
block_resync_queue_length+block_resync_errored_blocks - Garage node health (layout):
cluster_layout_node_connected(легенда{{ role_zone }}) - S3 requests /sec:
rate(api_s3_request_counter[5m])
15. Алерты ссылались на те же несуществующие метрики
В alerts.yml алерты GarageResyncErrors и GarageNodeUnstable использовали те же
фантомные имена (garage_block_resync_error_count, garage_rpc_node_health_is_up),
поэтому никогда не сработали бы. Исправлено на реальные:
block_resync_errored_blocks > 0 и cluster_layout_node_connected == 0.
После правки promtool check config → 6 rules found, все eval.
16. Relabel instance → hostname вместо IP (читаемые легенды)
По умолчанию instance = адрес скрейпа: у tproxy это 127.0.0.1:18081
(локальный конец SSH-туннеля), у garage 10.8.0.x:3903, у node 10.8.0.x:9100.
В Grafana легенды показывали IP — некрасиво и непонятно. Не путать: это НЕ
«мониторинг локального интерфейса», просто лейбл instance = транспорт туннеля.
Решение (на уровне Prometheus, не панелей) — relabel_configs в пром.yml:
relabel_configs:
- target_label: instance
replacement: vps03:8081 # для job tproxy
- source_labels: [__address__] # для garage/node — маппинг IP → hostname
regex: 10.8.0.2:3903
target_label: instance
replacement: bigbox:3903
Теперь легенды: vps01:3903, bigbox:3903, vps02:3903 (garage),
vps03:8081 (tproxy), vps01:9100 и т.д. (node). Правило: правим источник
(prom.yml relabel), а не легенды в каждой панели — консистентно везде
(панели, explore, алерты).
17. Grafana provisioning: дашборды — каждые 30с, datasources — только при старте
Дашборды перечитываются автоматически (updateIntervalSeconds, по умолчанию 30с),
а datasources провиженятся только при старте Grafana. После правки
datasources.yml — обязателен docker compose restart grafana.
Опыт: tproxy-server (WEB Proxy для Telegram Desktop) на vps03
Дата: 2026-08-31 Ситуация: развернули telegramdesktop/tproxy-server на vps03 (77.67.89.154, Debian 13): Caddy → tproxy-server:8080 → MTProxy:2398. Домен vps03.nixg.ru (HTTPS), порты 80/443 открыты из интернета.
A. Архитектура и порты
- Внешний вход:
https://vps03.nixg.ru:443→ Caddy →127.0.0.1:8080(tproxy-server) →127.0.0.1:2398(MTProxy). - tproxy-server config:
/etc/tproxy-server/config.json(600 root:tproxy). - Профили/секреты:
/etc/tproxy-server/profiles.json— массив профилей, можно несколько секретов (max_profiles: 32 в config). systemd читает их черезLoadCredential=profiles.json:/etc/tproxy-server/profiles.json(файл должен быть 600 root, иначе падает — тест TestLoadAcceptsSystemdCredentialReadPermissions). - Формат секрета: 16 байт = 32 hex (
openssl rand -hex 16), либо 17 байт с префиксомdd(fake-TLS-режим). - Добавить секрет: дописать профиль в profiles.json,
chmod 600,chown root:tproxy,systemctl restart tproxy-server→ в логеprofiles=N, readyz 200. - Отозвать секрет: убрать профиль из profiles.json + restart.
B. Admin-эндпоинты (только loopback 127.0.0.1:8081)
| Эндпоинт | Ответ |
|---|---|
| /healthz | всегда ok 200 (процесс жив) |
| /readyz | 200 ready / 503 backend unavailable — TCP-проба ко ВСЕМ backend-профилям (у нас 127.0.0.1:2398) |
| /metrics | Prometheus-формат (text/plain version 0.0.4), 13 счётчиков |
Метрики (все с префиксом tproxy_): sessions_live, streams_live,
backend_dials_in_flight, pending_bytes, pending_items, sessions_created_total,
sessions_closed_total, streams_opened_total, streams_rejected_total,
backend_dial_failures_total, bytes_up_total, bytes_down_total, limit_hits_total.
Ключевые для алертов: backend_dial_failures_total (рост = бэкенд недоступен),
limit_hits_total (DDOS/перегруз), sessions_live (активность).
C. Подключение к Prometheus (стек /opt/monitoring, bigbox) — РЕШЕНО через SSH-туннель
- vps03 НЕ в WG (10.8.0.0/24 = vps01/bigbox/vps02), поэтому прямого доступа
к 8081 с bigbox нет. Prometheus в стеке —
network_mode: host(видит внешние IP). - Изначальный план (nft-правило на vps03: разрешить TCP 8081 с publIP bigbox
178.176.197.2) не сработал: tproxy-server слушает
admin_listen: 127.0.0.1:8081, запрос с bigbox к77.67.89.154:8081вернулConnection refused(соединение упёрлось в отсутствующего наружу слушателя, а не в файрвол). - Решение: SSH-туннель bigbox → vps03 (паттерн systemd, как telegram-tunnel):
Prometheus скрейпит
# /etc/systemd/system/tproxy-tunnel.service (bigbox) User=estorozhenko ExecStart=/usr/bin/ssh -i /home/estorozhenko/.ssh/hostkeyVPS \ -L 127.0.0.1:18081:127.0.0.1:8081 -N \ -o ServerAliveInterval=30 -o ServerAliveCountMax=3 \ -o ExitOnForwardFailure=yes -o StrictHostKeyChecking=accept-new \ root@77.67.89.154 Restart=always127.0.0.1:18081. tproxy-server config/файрвол НЕ трогаются, метрики остаются на loopback. - ВНИМАНИЕ с портом: сначала взял
8081— но он на bigbox уже занят ICQ-веб-чатом (Converse.html на 0.0.0.0:8081), туннель конфликтовал и отдавал HTML чата вместо метрик. Порт на bigbox выбирать свободный (взял 18081). - readyz ходит ко ВСЕМ профилям: если добавить профиль с мёртвым бэкендом — readyz станет 503 (фича, учтена при алертах).
D. Грабли установки (уже в INSTALL_NOTES.md проекта tproxy-web)
- MTProxy-бинарь падал 203/EXEC:
chmod 755 /opt/MTProxy/objs/bin+ chown root:mtproxy + chmod 750. (см. /opt/hermes/tproxy-web/INSTALL_NOTES.md) go test ./...флакал на TestLoadAcceptsSystemdCredentialReadPermissions при запуске от root — обходится запуском тестов от не-root или пропуском.
# все три ноды отдают метрики:
curl -s -H "Authorization: Bearer TOKEN" http://10.8.0.1:3903/metrics | head
curl -s -H "Authorization: Bearer TOKEN" http://10.8.0.2:3903/metrics | head
curl -s -H "Authorization: Bearer TOKEN" http://10.8.0.4:3903/metrics | head
# → HTTP 200, ~90-110 КБ текста в Prometheus-формате
# кластер HEALTHY:
docker run --rm -v /opt/garage/garage.toml:/etc/garage.toml:ro -v /opt/garage/meta:/var/lib/garage/meta --entrypoint /garage dxflrs/garage:v2.1.0 status
# Prometheus: все таргеты UP (10/10):
curl http://127.0.0.1:9090/api/v1/targets
# garage x3, garage_health x3, node x3, prometheus self
# Grafana наружу:
curl -sk https://grafana.nixg.ru/api/health # → 200
# логи garage в Loki:
curl -G "http://127.0.0.1:3100/loki/api/v1/query_range" \
--data-urlencode 'query={container="garage"}' --data-urlencode 'limit=3'
25. vps03 подключён к WireGuard + node-exporter (2026-09-08)
Задача: мониторинг vps03 (77.67.89.154, Debian 13) системных метрик (диски/память/сеть/доступность) в Grafana, не светя порт наружу.
- Топология WG (была): hub = vps01 (10.8.0.1, pubkey ZAvz4xCE…), пиры bigbox (10.8.0.2), vps02 (10.8.0.4). Все слушают 51820.
- Новая нода: vps03 = 10.8.0.3, ключ
HBTzrS86SZ+…. vps03 инициирует туннель к hub (Endpoint 5.129.217.146:51820, AllowedIPs 10.8.0.0/24). - Главный грабль: hub видит vps03, но bigbox/vps02 НЕ могут ответить в
10.8.0.3: WireGuard дропает пакеты, чей src-адрес не в AllowedIPs пира.
Пришлось на bigbox и vps02 расширить AllowedIPs пира vps01 до
10.8.0.1/32, 10.8.0.3/32— тогда трафик к vps03 идёт через hub, а ответы возвращаются самому vps03. (vps03 → hub работает сразу, т.к. у vps03 AllowedIPs = 10.8.0.0/24; но в обратную сторону — нет.) - node-exporter на vps03: apt install, слушает
10.8.0.3:9100(в /etc/default/prometheus-node-exporter:ARGS="--web.listen-address=10.8.0.3:9100"). Публичный IP 77.67.89.154:9100 → connection refused (наружу не светит). - prometheus.yml: job
nodeполучает 4-й таргет10.8.0.3:9100(host=vps03, instance=vps03:9100) + relabel. - Дашборд:
grafana/dashboards/nodes.json(uidnodes, title "Nodes") — 6 панелей: availability (up{job="node"}, stat), disk free GB, memory available GB, network RX/TX B/s, load1. Provisioner импортирует автоматически. - Проверка:
curl http://127.0.0.1:9090/api/v1/targets→ node ×4 все up.
26. Per-node дашборды: сеть RX/TX + утилизация канала (2026-09-08)
Вместо одного nodes.json — 4 дашборда node-<host>.json
(uid node-<host>), генератор /tmp/gen_nodes_dash.py.
- Метрики сети в node-exporter 1.9 (apt, Debian 13): НЕ
node_net_bytes_*, аnode_network_receive_bytes_total/node_network_transmit_bytes_total(counter, device=) +node_network_speed_bytes(скорость линка, Б/с). - Утилизация канала:
(rate(rx[5m])+rate(tx[5m]))*8 / speed * 100. - Грабль: виртуалки дают
node_network_speed_bytes= -125000 (vps01 eth0, vps02 enp3s0; sysfs speed=-1 → exporter умножает на 125000, знак — т.к. -1). На физических (vps03 ens1, bigbox eno1) = 1.25e+08 (1000 Мбит/с). - Решение: для vps01/vps02 в формуле утилизации хардкод
125000000Б/с, для vps03/bigbox —node_network_speed_bytes. - Физические интерфейсы: vps01=eth0, vps02=enp3s0, vps03=ens1, bigbox=eno1. Контейнерные (docker0/veth*/br-*) исключены.
- Проверка: дашборды импортированы (БД: uid node-*), prom targets node ×4 up.
Что осталось сделать / TODO
- Развернуть стек (docker compose up -d) в /opt/monitoring
- Node-exporter на всех 4 хостах (10.8.0.x:9100; vps03 = 10.8.0.3)
- Дашборд Garage в Grafana (provisioning + JSON)
up{job="garage"}в Prometheus, Grafana :3001- Логи garage через promtail → Loki → Grafana
- Опубликовать Grafana: grafana.nixg.ru через caddy на vps02
- Mirror репозитория мониторинга в gitea (estorozhenko/monitoring)
- Сделать разные admin_token / metrics_token (сейчас совпадают)
- Поменять пароль Grafana с дефолтного (сейчас: пользователь estorozhenko, пароль сменён пользователем вручную через UI)