Files
monitoring/EXPERIENCE.md
T

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

Проверка результата

# все три ноды отдают метрики:
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)