Compare commits
2 Commits
413789ba22
...
dccc369d0b
| Author | SHA1 | Date | |
|---|---|---|---|
| dccc369d0b | |||
| 77ee26014d |
@@ -704,6 +704,73 @@ services:
|
|||||||
profiles: ["monitoring"]
|
profiles: ["monitoring"]
|
||||||
logging: *default-logging
|
logging: *default-logging
|
||||||
|
|
||||||
|
node-exporter:
|
||||||
|
# Метрики железа хоста (CPU, память, диск, сеть, load average) — то,
|
||||||
|
# чего нет ни в одном из приложенческих экспортеров выше. Без
|
||||||
|
# `network_mode: host` (не нужен: читаем /proc,/sys,/ хоста через
|
||||||
|
# bind-mount, а Prometheus достаёт их по имени сервиса во внутренней
|
||||||
|
# сети compose — так безопаснее, не расширяет сетевой доступ контейнера).
|
||||||
|
image: prom/node-exporter:v1.8.2
|
||||||
|
restart: unless-stopped
|
||||||
|
pid: host
|
||||||
|
volumes:
|
||||||
|
- /proc:/host/proc:ro
|
||||||
|
- /sys:/host/sys:ro
|
||||||
|
- /:/rootfs:ro
|
||||||
|
command:
|
||||||
|
- '--path.procfs=/host/proc'
|
||||||
|
- '--path.sysfs=/host/sys'
|
||||||
|
- '--path.rootfs=/rootfs'
|
||||||
|
- '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'
|
||||||
|
# Не публикуем порт наружу вообще (не 127.0.0.1:9100, а совсем без
|
||||||
|
# ports) — Prometheus ходит к нему по внутренней сети compose
|
||||||
|
# (`node-exporter:9100`), публикация на хост для этого не нужна.
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "wget -q -O- http://127.0.0.1:9100/metrics >/dev/null || exit 1"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 10
|
||||||
|
start_period: 10s
|
||||||
|
profiles: ["monitoring"]
|
||||||
|
logging: *default-logging
|
||||||
|
|
||||||
|
cadvisor:
|
||||||
|
# Метрики по контейнерам (CPU/память каждого) — отвечает на вопрос
|
||||||
|
# «какой из контейнеров ест ресурсы», в отличие от node-exporter
|
||||||
|
# (только хост целиком). Дороже node-exporter по CPU/RAM (собственные
|
||||||
|
# ~60-120 МБ RSS + периодический обход cgroups) — на сервере 8 ГБ/4 CPU
|
||||||
|
# с ~13 контейнерами это приемлемо, но не бесплатно; `--docker_only`
|
||||||
|
# и `--disable_metrics` ниже отключают часть коллекторов сверх дефолта
|
||||||
|
# cAdvisor (который уже отключает cpu_topology/hugetlb/memory_numa/
|
||||||
|
# process/sched/tcp/udp и т.п.) — здесь дополнительно per-core CPU,
|
||||||
|
# perf_event и дисковые метрики (диск и так покрыт node-exporter'ом,
|
||||||
|
# дублировать через cAdvisor незачем). Список допустимых значений —
|
||||||
|
# `cadvisor -help` (в версии образа меняется, не все имена стабильны
|
||||||
|
# между релизами — при апгрейде образа сверяться с `-help`).
|
||||||
|
image: gcr.io/cadvisor/cadvisor:v0.49.2
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- /:/rootfs:ro
|
||||||
|
- /var/run:/var/run:ro
|
||||||
|
- /sys:/sys:ro
|
||||||
|
- /var/lib/docker/:/var/lib/docker:ro
|
||||||
|
# Только чтение — cAdvisor не должен иметь возможность управлять
|
||||||
|
# контейнерами, ему нужен только список и статистика.
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
command:
|
||||||
|
- '--docker_only=true'
|
||||||
|
- '--disable_metrics=percpu,perf_event,diskIO,disk,app'
|
||||||
|
# Без ports вообще — тот же принцип, что и у node-exporter: Prometheus
|
||||||
|
# достаёт метрики по имени сервиса (`cadvisor:8080`) внутри сети compose.
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "wget -q -O- http://127.0.0.1:8080/healthz >/dev/null || exit 1"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 10
|
||||||
|
start_period: 15s
|
||||||
|
profiles: ["monitoring"]
|
||||||
|
logging: *default-logging
|
||||||
|
|
||||||
grafana:
|
grafana:
|
||||||
image: grafana/grafana:13.1.0
|
image: grafana/grafana:13.1.0
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|||||||
@@ -60,3 +60,58 @@ groups:
|
|||||||
# суммаризация встанет (задачи будут копиться в очереди summarize,
|
# суммаризация встанет (задачи будут копиться в очереди summarize,
|
||||||
# см. также алерт QueueGrowing). Проверить
|
# см. также алерт QueueGrowing). Проверить
|
||||||
# `docker compose ps llm` / `llm-gpu` и `docker compose logs llm`.
|
# `docker compose ps llm` / `llm-gpu` и `docker compose logs llm`.
|
||||||
|
|
||||||
|
# Железо хоста (job `node` — node-exporter). Пороги подобраны под
|
||||||
|
# конкретный сервер 1gb: 8 ГБ RAM, 4 CPU, 50 ГБ диска — если сервер
|
||||||
|
# сменится, пересчитать.
|
||||||
|
- name: vidconf-host
|
||||||
|
rules:
|
||||||
|
# MemAvailable — уже честная оценка Linux с учётом того, что легко
|
||||||
|
# освобождаемый page cache/buffers не в счёт (в отличие от naive
|
||||||
|
# used = total - free). 10% от 8 ГБ ≈ 800 МБ — `for: 10m`, чтобы не
|
||||||
|
# дёргать на кратковременный всплеск (например, разовый всплеск
|
||||||
|
# transcribe/summarize), но успеть среагировать до OOM killer.
|
||||||
|
- alert: HostMemoryLow
|
||||||
|
expr: (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100 < 10
|
||||||
|
for: 10m
|
||||||
|
labels:
|
||||||
|
severity: warning
|
||||||
|
annotations:
|
||||||
|
summary: "Мало свободной памяти на хосте"
|
||||||
|
description: >-
|
||||||
|
Свободно {{ $value | printf "%.1f" }}% RAM дольше 10 минут
|
||||||
|
(порог 10% ≈ 800 МБ из 8 ГБ). Смотреть, какой контейнер ест
|
||||||
|
память — дашборд «Хост и контейнеры», топ по памяти (cAdvisor).
|
||||||
|
|
||||||
|
# 50 ГБ диска — 10% ≈ 5 ГБ. `for: 15m` (не мгновенно): диск не растёт
|
||||||
|
# так же резко, как память, ложные срабатывания на всплеск не грозят,
|
||||||
|
# но и разовая проверка на границе некритична — 15 минут отсекает шум.
|
||||||
|
- alert: HostDiskLow
|
||||||
|
expr: (node_filesystem_avail_bytes{mountpoint="/",fstype!="tmpfs"} / node_filesystem_size_bytes{mountpoint="/",fstype!="tmpfs"}) * 100 < 10
|
||||||
|
for: 15m
|
||||||
|
labels:
|
||||||
|
severity: warning
|
||||||
|
annotations:
|
||||||
|
summary: "Мало места на диске хоста"
|
||||||
|
description: >-
|
||||||
|
Свободно {{ $value | printf "%.1f" }}% диска дольше 15 минут
|
||||||
|
(порог 10% ≈ 5 ГБ из 50 ГБ). Частые причины на этом проекте —
|
||||||
|
записи транскрибации (`recordings`), логи docker, образы/слои
|
||||||
|
после пересборки — проверить `docker system df`.
|
||||||
|
|
||||||
|
# 4 CPU. Порог 90% и `for: 15m` — сознательно строже по времени, чем
|
||||||
|
# у памяти/диска: кратковременные пики от пайплайна пост-обработки
|
||||||
|
# (транскрибация/суммаризация) — это ожидаемая, не аварийная нагрузка,
|
||||||
|
# алерт должен ловить именно устойчивую перегрузку, а не обычный всплеск.
|
||||||
|
- alert: HostCpuHigh
|
||||||
|
expr: 100 - (avg(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 90
|
||||||
|
for: 15m
|
||||||
|
labels:
|
||||||
|
severity: warning
|
||||||
|
annotations:
|
||||||
|
summary: "Устойчиво высокая загрузка CPU хоста"
|
||||||
|
description: >-
|
||||||
|
Загрузка CPU {{ $value | printf "%.1f" }}% дольше 15 минут
|
||||||
|
подряд (порог 90% из 4 ядер). Смотреть топ контейнеров по CPU
|
||||||
|
(дашборд «Хост и контейнеры», cAdvisor) и латентность API —
|
||||||
|
возможно, не хватает уровня AI/ресурсов под нагрузку.
|
||||||
|
|||||||
245
deploy/monitoring/grafana/dashboards/host.json
Normal file
245
deploy/monitoring/grafana/dashboards/host.json
Normal file
@@ -0,0 +1,245 @@
|
|||||||
|
{
|
||||||
|
"title": "Хост и контейнеры",
|
||||||
|
"description": "CPU/RAM/диск/сеть хоста (node-exporter) и разбивка по контейнерам (cAdvisor) — профиль compose monitoring. Пороги на панелях согласованы с deploy/monitoring/alerts.yml (группа vidconf-host).",
|
||||||
|
"uid": "vidconf-host",
|
||||||
|
"editable": false,
|
||||||
|
"timezone": "browser",
|
||||||
|
"schemaVersion": 39,
|
||||||
|
"version": 1,
|
||||||
|
"time": { "from": "now-6h", "to": "now" },
|
||||||
|
"refresh": "30s",
|
||||||
|
"tags": ["vidconf", "host"],
|
||||||
|
"panels": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"title": "Загрузка CPU",
|
||||||
|
"description": "100 - idle, усреднено по всем ядрам. Порог алерта HostCpuHigh — 90% дольше 15 минут, см. alerts.yml.",
|
||||||
|
"type": "timeseries",
|
||||||
|
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 0 },
|
||||||
|
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": { "unit": "percent", "max": 100, "min": 0, "custom": { "drawStyle": "line", "fillOpacity": 10 } },
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
||||||
|
"expr": "100 - (avg(rate(node_cpu_seconds_total{mode=\"idle\"}[5m])) * 100)",
|
||||||
|
"legendFormat": "CPU busy",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"title": "Load average",
|
||||||
|
"description": "node_load1/5/15 — на 4-ядерном сервере устойчивое значение выше ~4 означает очередь на CPU.",
|
||||||
|
"type": "timeseries",
|
||||||
|
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 0 },
|
||||||
|
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": { "custom": { "drawStyle": "line", "fillOpacity": 5 } },
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{ "datasource": { "type": "prometheus", "uid": "prometheus" }, "expr": "node_load1", "legendFormat": "1 мин", "refId": "A" },
|
||||||
|
{ "datasource": { "type": "prometheus", "uid": "prometheus" }, "expr": "node_load5", "legendFormat": "5 мин", "refId": "B" },
|
||||||
|
{ "datasource": { "type": "prometheus", "uid": "prometheus" }, "expr": "node_load15", "legendFormat": "15 мин", "refId": "C" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"title": "Использование RAM",
|
||||||
|
"description": "(1 - MemAvailable/MemTotal) — MemAvailable уже учитывает легко освобождаемый page cache/buffers. Порог алерта HostMemoryLow — доступно <10% дольше 10 минут, см. alerts.yml.",
|
||||||
|
"type": "timeseries",
|
||||||
|
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 8 },
|
||||||
|
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": { "unit": "percent", "max": 100, "min": 0, "custom": { "drawStyle": "line", "fillOpacity": 10 } },
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
||||||
|
"expr": "(1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100",
|
||||||
|
"legendFormat": "RAM used",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4,
|
||||||
|
"title": "Своп (использовано)",
|
||||||
|
"description": "SwapTotal - SwapFree. На этом сервере swap не заведён под мониторинг отдельным алертом — рост от нуля сам по себе сигнал, что памяти уже не хватает (см. HostMemoryLow).",
|
||||||
|
"type": "timeseries",
|
||||||
|
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 8 },
|
||||||
|
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": { "unit": "decbytes", "custom": { "drawStyle": "line", "fillOpacity": 10 } },
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
||||||
|
"expr": "node_memory_SwapTotal_bytes - node_memory_SwapFree_bytes",
|
||||||
|
"legendFormat": "swap used",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 5,
|
||||||
|
"title": "Свободно на диске (/)",
|
||||||
|
"description": "node_filesystem_avail_bytes для корня. Порог алерта HostDiskLow — <10% (≈5 ГБ из 50 ГБ) дольше 15 минут.",
|
||||||
|
"type": "stat",
|
||||||
|
"gridPos": { "h": 4, "w": 6, "x": 0, "y": 16 },
|
||||||
|
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"unit": "decbytes",
|
||||||
|
"thresholds": { "mode": "absolute", "steps": [{ "color": "red", "value": null }, { "color": "green", "value": 5368709120 }] }
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
||||||
|
"expr": "node_filesystem_avail_bytes{mountpoint=\"/\",fstype!=\"tmpfs\"}",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 6,
|
||||||
|
"title": "RAM сейчас, %",
|
||||||
|
"description": "Текущий снимок панели «Использование RAM». Порог совпадает с HostMemoryLow (used > 90%).",
|
||||||
|
"type": "stat",
|
||||||
|
"gridPos": { "h": 4, "w": 6, "x": 6, "y": 16 },
|
||||||
|
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"unit": "percent",
|
||||||
|
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }, { "color": "red", "value": 90 }] }
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
||||||
|
"expr": "(1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 7,
|
||||||
|
"title": "Диск сейчас, %",
|
||||||
|
"description": "Текущий снимок использования корневого раздела. Порог совпадает с HostDiskLow (used > 90%).",
|
||||||
|
"type": "stat",
|
||||||
|
"gridPos": { "h": 4, "w": 6, "x": 12, "y": 16 },
|
||||||
|
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"unit": "percent",
|
||||||
|
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }, { "color": "red", "value": 90 }] }
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
||||||
|
"expr": "(1 - node_filesystem_avail_bytes{mountpoint=\"/\",fstype!=\"tmpfs\"} / node_filesystem_size_bytes{mountpoint=\"/\",fstype!=\"tmpfs\"}) * 100",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 8,
|
||||||
|
"title": "CPU сейчас, %",
|
||||||
|
"description": "Текущий снимок загрузки CPU. Порог совпадает с HostCpuHigh (>90%).",
|
||||||
|
"type": "stat",
|
||||||
|
"gridPos": { "h": 4, "w": 6, "x": 18, "y": 16 },
|
||||||
|
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"unit": "percent",
|
||||||
|
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }, { "color": "red", "value": 90 }] }
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
||||||
|
"expr": "100 - (avg(rate(node_cpu_seconds_total{mode=\"idle\"}[5m])) * 100)",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 9,
|
||||||
|
"title": "Сетевой трафик",
|
||||||
|
"description": "rx/tx по физическим интерфейсам хоста (исключены lo/veth/docker/br — это внутренние интерфейсы контейнеров, а не реальный сетевой трафик сервера).",
|
||||||
|
"type": "timeseries",
|
||||||
|
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 20 },
|
||||||
|
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": { "unit": "Bps", "custom": { "drawStyle": "line", "fillOpacity": 5 } },
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
||||||
|
"expr": "rate(node_network_receive_bytes_total{device!~\"lo|veth.*|docker.*|br-.*\"}[5m])",
|
||||||
|
"legendFormat": "rx {{device}}",
|
||||||
|
"refId": "A"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
||||||
|
"expr": "rate(node_network_transmit_bytes_total{device!~\"lo|veth.*|docker.*|br-.*\"}[5m])",
|
||||||
|
"legendFormat": "tx {{device}}",
|
||||||
|
"refId": "B"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 10,
|
||||||
|
"title": "Топ контейнеров по CPU",
|
||||||
|
"description": "Источник — cAdvisor (job cadvisor). Отвечает на вопрос «кто из контейнеров грузит CPU» при срабатывании HostCpuHigh.",
|
||||||
|
"type": "timeseries",
|
||||||
|
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 20 },
|
||||||
|
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": { "unit": "percentunit", "custom": { "drawStyle": "line", "fillOpacity": 10, "stacking": { "mode": "normal" } } },
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
||||||
|
"expr": "topk(5, sum by (name) (rate(container_cpu_usage_seconds_total{name!=\"\"}[5m])))",
|
||||||
|
"legendFormat": "{{name}}",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 11,
|
||||||
|
"title": "Топ контейнеров по памяти",
|
||||||
|
"description": "container_memory_working_set_bytes — это то, что реально учитывает cgroup OOM killer (в отличие от RSS), источник — cAdvisor.",
|
||||||
|
"type": "timeseries",
|
||||||
|
"gridPos": { "h": 8, "w": 24, "x": 0, "y": 28 },
|
||||||
|
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": { "unit": "decbytes", "custom": { "drawStyle": "line", "fillOpacity": 10, "stacking": { "mode": "normal" } } },
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
||||||
|
"expr": "topk(5, container_memory_working_set_bytes{name!=\"\"})",
|
||||||
|
"legendFormat": "{{name}}",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
# Конфигурация Prometheus (devops) — сбор метрик backend,
|
# Конфигурация Prometheus (devops) — сбор метрик backend,
|
||||||
# PostgreSQL, Redis и локального LLM-сервера. Поднимается compose-профилем
|
# PostgreSQL, Redis, железа хоста, контейнеров и локального LLM-сервера.
|
||||||
# `monitoring` (deploy/docker-compose.yml, сервис `prometheus`).
|
# Поднимается compose-профилем `monitoring` (deploy/docker-compose.yml,
|
||||||
|
# сервис `prometheus`).
|
||||||
#
|
#
|
||||||
# Имена метрик backend (`vidconf_http_request_duration_seconds`,
|
# Имена метрик backend (`vidconf_http_request_duration_seconds`,
|
||||||
# `vidconf_pipeline_sessions`, `vidconf_celery_queue_depth`) — КОНТРАКТ с
|
# `vidconf_pipeline_sessions`, `vidconf_celery_queue_depth`) — КОНТРАКТ с
|
||||||
@@ -33,6 +34,22 @@ scrape_configs:
|
|||||||
static_configs:
|
static_configs:
|
||||||
- targets: ["redis-exporter:9121"]
|
- targets: ["redis-exporter:9121"]
|
||||||
|
|
||||||
|
# Хост целиком: CPU, память, диск, сеть, load average (профиль monitoring
|
||||||
|
# — сервис node-exporter). Единственный источник, который покажет
|
||||||
|
# нехватку памяти/CPU на сервере, если она не проявится как рост
|
||||||
|
# латентности API (см. дашборд host.json).
|
||||||
|
- job_name: node
|
||||||
|
static_configs:
|
||||||
|
- targets: ["node-exporter:9100"]
|
||||||
|
|
||||||
|
# Метрики по каждому контейнеру (CPU/память отдельно у backend, worker,
|
||||||
|
# postgres и т.д. — профиль monitoring, сервис cadvisor). Отвечает на
|
||||||
|
# вопрос «какой из контейнеров ест ресурсы», в отличие от job `node`
|
||||||
|
# (только хост целиком).
|
||||||
|
- job_name: cadvisor
|
||||||
|
static_configs:
|
||||||
|
- targets: ["cadvisor:8080"]
|
||||||
|
|
||||||
# Локальный LLM-сервер (llama.cpp, LLAMA_ARG_ENDPOINT_METRICS=1). Адрес
|
# Локальный LLM-сервер (llama.cpp, LLAMA_ARG_ENDPOINT_METRICS=1). Адрес
|
||||||
# `llm:8080` разрешается ОДНИМ из двух compose-сервисов в зависимости от
|
# `llm:8080` разрешается ОДНИМ из двух compose-сервисов в зависимости от
|
||||||
# выбранного при установке пресета — `llm` (CPU, профиль `llm`, уровни
|
# выбранного при установке пресета — `llm` (CPU, профиль `llm`, уровни
|
||||||
|
|||||||
@@ -18,10 +18,10 @@ import { formatRecurrenceSummary } from '@/lib/recurrenceFormat'
|
|||||||
const PAGE_SIZE = 10
|
const PAGE_SIZE = 10
|
||||||
|
|
||||||
const STATUS_FILTERS: { value: ConferenceStatus | 'all'; label: string }[] = [
|
const STATUS_FILTERS: { value: ConferenceStatus | 'all'; label: string }[] = [
|
||||||
{ value: 'all', label: 'Все' },
|
|
||||||
{ value: 'scheduled', label: 'Запланированные' },
|
{ value: 'scheduled', label: 'Запланированные' },
|
||||||
{ value: 'active', label: 'Активные' },
|
{ value: 'active', label: 'Активные' },
|
||||||
{ value: 'ended', label: 'Завершённые' },
|
{ value: 'ended', label: 'Завершённые' },
|
||||||
|
{ value: 'all', label: 'Все' },
|
||||||
]
|
]
|
||||||
|
|
||||||
function StatusBadge({ conference }: { conference: AdminConferenceOut }) {
|
function StatusBadge({ conference }: { conference: AdminConferenceOut }) {
|
||||||
@@ -287,7 +287,7 @@ function InviteModal({ conference, onClose }: { conference: AdminConferenceOut;
|
|||||||
* блок «table-card», адаптированный под сущность «конференция»).
|
* блок «table-card», адаптированный под сущность «конференция»).
|
||||||
*/
|
*/
|
||||||
export function AdminConferencesTab() {
|
export function AdminConferencesTab() {
|
||||||
const [statusFilter, setStatusFilter] = useState<ConferenceStatus | 'all'>('all')
|
const [statusFilter, setStatusFilter] = useState<ConferenceStatus | 'all'>('scheduled')
|
||||||
const [searchInput, setSearchInput] = useState('')
|
const [searchInput, setSearchInput] = useState('')
|
||||||
const [search, setSearch] = useState('')
|
const [search, setSearch] = useState('')
|
||||||
const [offset, setOffset] = useState(0)
|
const [offset, setOffset] = useState(0)
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ const STATUS_FILTERS: { value: 'active' | 'blocked' | 'all'; label: string }[] =
|
|||||||
*/
|
*/
|
||||||
export function AdminUsersTab() {
|
export function AdminUsersTab() {
|
||||||
const { user: currentUser } = useAuth()
|
const { user: currentUser } = useAuth()
|
||||||
const [statusFilter, setStatusFilter] = useState<'active' | 'blocked' | 'all'>('all')
|
const [statusFilter, setStatusFilter] = useState<'active' | 'blocked' | 'all'>('active')
|
||||||
const [searchInput, setSearchInput] = useState('')
|
const [searchInput, setSearchInput] = useState('')
|
||||||
const [search, setSearch] = useState('')
|
const [search, setSearch] = useState('')
|
||||||
const [offset, setOffset] = useState(0)
|
const [offset, setOffset] = useState(0)
|
||||||
|
|||||||
Reference in New Issue
Block a user