mirror of
https://gitverse.ru/kpa39l/monitoring.git
synced 2026-09-29 09:55:09 +00:00
455 lines
26 KiB
Markdown
455 lines
26 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).
|
||
|
||
## Опыт: 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
|
||
корректно видит недоступность шлюза.
|
||
|
||
### 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). Пароль задаётся при создании.
|
||
|
||
Проверка после создания:
|
||
```bash
|
||
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 дашборда ссылалась на встроенный датасорс:
|
||
|
||
```json
|
||
"annotations": { "list": [ { "builtIn": 1,
|
||
"datasource": {"type": "grafana", "uid": "__grafana__"}, ... } ] }
|
||
```
|
||
|
||
- `__grafana__` — встроенный datasource Grafana (аннотации/алерты). В нашей
|
||
БД `data_source` его НЕТ (только Prometheus и Loki) → Grafana 11 OSS не
|
||
может его найти и показывает ошибку. Панели не используют аннотации —
|
||
секция добавляется в JSON автоматически при создании (шаблон),
|
||
но в файле она бесполезна.
|
||
- **Фикс:** очистить `annotations.list` в файле дашборда:
|
||
```bash
|
||
jq '.annotations.list = []' grafana/dashboards/vinograd-wan.json > /tmp/vw.json \
|
||
&& mv /tmp/vw.json grafana/dashboards/vinograd-wan.json
|
||
```
|
||
Провайдер дашбордов перечитывает файл **каждые 30с** (рестарт не нужен),
|
||
в БД появляется version 2 с `"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]` отдельный адрес:
|
||
|
||
```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, работает всё.
|
||
|
||
## Опыт: дашборд 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_blocks`
|
||
- `garage_rpc_node_health_is_up` — в реальности `cluster_layout_node_connected`
|
||
- `garage_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:
|
||
```yaml
|
||
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):
|
||
```ini
|
||
# /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=always
|
||
```
|
||
Prometheus скрейпит `127.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'
|
||
```
|
||
|
||
## Что осталось сделать / 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) |