docs(monitoring): описать контейнерный экспортер и модель безопасности
Новый раздел про container-exporter/docker-socket-proxy: зачем свой экспортер вместо cAdvisor, какие метрики отдаёт, почему доступ к докер-сокету через прокси безопасен. Дополнена таблица метрик backend (vidconf_host_info).
This commit is contained in:
@@ -11,14 +11,18 @@
|
|||||||
| `postgres-exporter` | `quay.io/prometheuscommunity/postgres-exporter:v0.20.1` | — (внутренний) | метрики PostgreSQL |
|
| `postgres-exporter` | `quay.io/prometheuscommunity/postgres-exporter:v0.20.1` | — (внутренний) | метрики PostgreSQL |
|
||||||
| `redis-exporter` | `oliver006/redis_exporter:v1.87.0-alpine` | — (внутренний) | метрики Redis |
|
| `redis-exporter` | `oliver006/redis_exporter:v1.87.0-alpine` | — (внутренний) | метрики Redis |
|
||||||
| `node-exporter` | `prom/node-exporter:v1.8.2` | — (внутренний) | метрики хоста: CPU, память, диск, сеть, load average |
|
| `node-exporter` | `prom/node-exporter:v1.8.2` | — (внутренний) | метрики хоста: CPU, память, диск, сеть, load average |
|
||||||
|
| `docker-socket-proxy` | `tecnativa/docker-socket-proxy:v0.5.0` | — (внутренний) | read-only прокси к Docker Engine API для `container-exporter` |
|
||||||
|
| `container-exporter` | сборка из `deploy/monitoring/container-exporter/` | — (внутренний) | метрики CPU/память/сеть в разбивке по контейнерам |
|
||||||
| `grafana` | `grafana/grafana:13.1.0` | `3001` (внутри контейнера `3000`) | дашборды «Пайплайны пост-обработки» и «Хост и контейнеры» |
|
| `grafana` | `grafana/grafana:13.1.0` | `3001` (внутри контейнера `3000`) | дашборды «Пайплайны пост-обработки» и «Хост и контейнеры» |
|
||||||
|
|
||||||
`node-exporter` не публикует порт на хост вообще (не только 127.0.0.1) —
|
`node-exporter`/`docker-socket-proxy`/`container-exporter` не публикуют
|
||||||
Prometheus ходит к нему по имени сервиса во внутренней сети compose,
|
порт на хост вообще (не только 127.0.0.1) — Prometheus и сам экспортер
|
||||||
|
ходят друг к другу по имени сервиса во внутренней сети compose,
|
||||||
публикация на хост для этого не нужна.
|
публикация на хост для этого не нужна.
|
||||||
|
|
||||||
**cAdvisor сознательно не используется** (разбивки метрик по контейнерам
|
### 1.1. Метрики по контейнерам — свой экспортер вместо cAdvisor
|
||||||
в Grafana нет): Docker Engine на сервере `1gb` использует
|
|
||||||
|
**cAdvisor не используется**: Docker Engine на сервере `1gb` использует
|
||||||
containerd-снапшоттер (`docker info` → `driver-type:
|
containerd-снапшоттер (`docker info` → `driver-type:
|
||||||
io.containerd.snapshotter.v1`), а не классический overlay2-драйвер, и
|
io.containerd.snapshotter.v1`), а не классический overlay2-драйвер, и
|
||||||
cAdvisor (проверено на v0.49.2 и v0.52.1, с `--docker_only` и без, через
|
cAdvisor (проверено на v0.49.2 и v0.52.1, с `--docker_only` и без, через
|
||||||
@@ -26,15 +30,48 @@ cAdvisor (проверено на v0.49.2 и v0.52.1, с `--docker_only` и бе
|
|||||||
read-write layer контейнеров — падает с «failed to identify the
|
read-write layer контейнеров — падает с «failed to identify the
|
||||||
read-write layer ID», метрики есть только по корневому cgroup. Открытая
|
read-write layer ID», метрики есть только по корневому cgroup. Открытая
|
||||||
проблема совместимости cAdvisor с containerd image store, флагами не
|
проблема совместимости cAdvisor с containerd image store, флагами не
|
||||||
чинится — см. `.forcc/JOURNAL.md`. Если на другом сервере используется
|
чинится — см. `.forcc/JOURNAL.md`.
|
||||||
классический overlay2, cAdvisor можно добавить обратно по тому же
|
|
||||||
образцу, что и `node-exporter` (job `cadvisor` в `prometheus.yml`,
|
Вместо этого — свой минимальный экспортер (`container-exporter`,
|
||||||
таргет `cadvisor:8080`, без публикации портов).
|
`deploy/monitoring/container-exporter/exporter.py`, Python/aiohttp/
|
||||||
|
`prometheus_client`) поверх Docker Engine API: `GET /containers/json` +
|
||||||
|
`GET /containers/{id}/stats?stream=false`. Эти эндпойнты не зависят от
|
||||||
|
storage-driver'а — работают и с containerd-снапшоттером, и с overlay2.
|
||||||
|
Опрос контейнеров идёт параллельно в фоновой задаче (свой интервал,
|
||||||
|
не завязан на scrape Prometheus) — `stats?stream=false` не мгновенен
|
||||||
|
(Docker считает CPU-дельту по двум внутренним замерам с разницей ~1с),
|
||||||
|
линейный опрос дюжины контейнеров легко вышел бы за scrape-интервал.
|
||||||
|
Метрики (лейбл `name` — имя контейнера):
|
||||||
|
|
||||||
|
- `vidconf_container_cpu_percent` — % от одного ядра, как `docker stats`.
|
||||||
|
- `vidconf_container_memory_usage_bytes` / `_limit_bytes` — working set
|
||||||
|
(без переиспользуемого page cache) и лимит памяти.
|
||||||
|
- `vidconf_container_network_rx_bytes` / `_tx_bytes` — суммарно по
|
||||||
|
интерфейсам, счётчик со старта контейнера.
|
||||||
|
|
||||||
|
**Безопасность: доступ к `/var/run/docker.sock` равносилен root на
|
||||||
|
хосте.** Флаг `:ro` при монтировании сокета не спасает — он ограничивает
|
||||||
|
права на файл-ноду, а не на протокол: через сокет можно поднять
|
||||||
|
привилегированный контейнер и получить хост. Поэтому сокет НЕ
|
||||||
|
монтируется напрямую в `container-exporter` — между ними стоит
|
||||||
|
`docker-socket-proxy` (`tecnativa/docker-socket-proxy`), которому
|
||||||
|
разрешены только `GET`-запросы по контейнерам (`CONTAINERS=1`, `POST=0`
|
||||||
|
— дефолт образа, выписан явно). Даже полная компрометация
|
||||||
|
`container-exporter` (например, через уязвимость в его зависимостях) не
|
||||||
|
даёт управлять Docker — прокси физически не пропустит `POST`. Ни один
|
||||||
|
из двух сервисов не публикует портов наружу.
|
||||||
|
|
||||||
|
Если на другом сервере используется классический overlay2 и хочется
|
||||||
|
именно cAdvisor — можно добавить его по тому же образцу, что и
|
||||||
|
`node-exporter` (свой job в `prometheus.yml`, без публикации портов),
|
||||||
|
но тогда придётся решать ту же проблему монтирования сокета отдельно
|
||||||
|
(cAdvisor тоже требует доступ к Docker API).
|
||||||
|
|
||||||
Файлы: `deploy/monitoring/prometheus.yml`, `deploy/monitoring/alerts.yml`,
|
Файлы: `deploy/monitoring/prometheus.yml`, `deploy/monitoring/alerts.yml`,
|
||||||
`deploy/monitoring/grafana/provisioning/` (datasource + провайдер
|
`deploy/monitoring/grafana/provisioning/` (datasource + провайдер
|
||||||
дашбордов), `deploy/monitoring/grafana/dashboards/pipelines.json`,
|
дашбордов), `deploy/monitoring/grafana/dashboards/pipelines.json`,
|
||||||
`deploy/monitoring/grafana/dashboards/host.json`.
|
`deploy/monitoring/grafana/dashboards/host.json`,
|
||||||
|
`deploy/monitoring/container-exporter/` (код экспортера).
|
||||||
|
|
||||||
## 2. Запуск
|
## 2. Запуск
|
||||||
|
|
||||||
@@ -76,6 +113,13 @@ ssh -L 9090:127.0.0.1:9090 -L 3001:127.0.0.1:3001 <user>@<host>
|
|||||||
- `vidconf_celery_queue_depth` (gauge, `queue`) — глубина очередей Celery
|
- `vidconf_celery_queue_depth` (gauge, `queue`) — глубина очередей Celery
|
||||||
(`transcription`/`summarize`/`notify`/`celery`, redis `LLEN`), карта
|
(`transcription`/`summarize`/`notify`/`celery`, redis `LLEN`), карта
|
||||||
очередей — `docs/deploy/scaling.md`.
|
очередей — `docs/deploy/scaling.md`.
|
||||||
|
- `vidconf_host_info` (gauge, всегда `1`, лейблы `cpus`/`ram_mb`/`gpu_name`/
|
||||||
|
`vram_mb`) — info-метрика обнаруженного `install.sh` железа (`HW_*` в
|
||||||
|
`.env`, ADR-004). Источник плашки с характеристиками сервера в дашборде
|
||||||
|
«Хост и контейнеры» — живые CPU/RAM/диск там же берутся из
|
||||||
|
node-exporter, а GPU node-exporter не знает вообще, поэтому только эта
|
||||||
|
метрика. `«—»` в лейбле — `install.sh` не запускался (dev) либо
|
||||||
|
видеокарта не обнаружена.
|
||||||
|
|
||||||
Job `llm` в `prometheus.yml` скрейпит `llm:8080/metrics`
|
Job `llm` в `prometheus.yml` скрейпит `llm:8080/metrics`
|
||||||
(`LLAMA_ARG_ENDPOINT_METRICS=1`) — этот адрес резолвится ЛИБО сервисом
|
(`LLAMA_ARG_ENDPOINT_METRICS=1`) — этот адрес резолвится ЛИБО сервисом
|
||||||
|
|||||||
Reference in New Issue
Block a user