mirror of
https://gitverse.ru/kpa39l/monitoring.git
synced 2026-09-29 09:55:09 +00:00
162 lines
8.2 KiB
Markdown
162 lines
8.2 KiB
Markdown
# Опыт эксплуатации: мониторинг 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]` отдельный адрес:
|
||
|
||
```toml
|
||
[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
|
||
|
||
- [x] Развернуть стек (docker compose up -d) в /opt/monitoring
|
||
- [x] Node-exporter на всех 3 хостах (10.8.0.x:9100)
|
||
- [x] Дашборд Garage в Grafana (provisioning + JSON)
|
||
- [x] `up{job="garage"}` в Prometheus, Grafana :3001
|
||
- [x] Логи garage через promtail → Loki → Grafana
|
||
- [x] Опубликовать Grafana: grafana.nixg.ru через caddy на vps02
|
||
- [x] Mirror репозитория мониторинга в gitea (estorozhenko/monitoring)
|
||
- [ ] Сделать разные admin_token / metrics_token (сейчас совпадают)
|
||
- [ ] Поменять пароль Grafana с дефолтного (сейчас: пользователь estorozhenko,
|
||
пароль сменён пользователем вручную через UI) |