Files
monitoring/EXPERIENCE.md
T

12 KiB
Raw Blame History

Опыт эксплуатации: мониторинг Garage v2.1 через Prometheus

Дата: 2026-08-30 Ситуация: кластер Garage v2.1 (RF=3) на vps01 + bigbox + vps02, WireGuard 10.8.0.0/24. Задача: вывести статус кластера в браузер (Grafana + Prometheus + Loki).

Ключевые находки / грабли

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, работает всё.

Опыт: 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)

  • 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), job 'tproxy' в prometheus.yml, targets ['77.67.89.154:8081'].
  • ВАЖНО: admin-эндпоинты слушают только loopback. Открывать наружу ТОЛЬКО по источнику (ip saddr bigbox), не публиковать всем.
  • 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'

Что осталось сделать / TODO

  • Развернуть стек (docker compose up -d) в /opt/monitoring
  • Node-exporter на всех 3 хостах (10.8.0.x:9100)
  • Дашборд 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)