Разбивка по контейнерам (CPU/память/сеть) — то, что не смог дать
cAdvisor из-за несовместимости с containerd-снапшоттером сервера 1gb
(убран в 7f5c888). Свой минимальный сервис container-exporter (Python/
aiohttp/prometheus_client) опрашивает Docker Engine API параллельно в
фоновой задаче, не завязываясь на scrape-интервал Prometheus.
Доступ к докер-сокету изолирован через docker-socket-proxy: экспортеру
разрешены только GET /containers/json и /containers/*/stats, любые
изменяющие запросы блокируются на уровне прокси (POST=0) — полная
компрометация экспортера не даёт управлять Docker. Ни один из двух
сервисов не публикует портов наружу.
В host.json возвращены панели «Топ контейнеров по CPU/памяти» на новых
метриках vidconf_container_* (в 0.0.9 их убрали вместе с cAdvisor).
355 lines
15 KiB
JSON
355 lines
15 KiB
JSON
{
|
||
"title": "Хост и контейнеры",
|
||
"description": "CPU/RAM/диск/сеть хоста (node-exporter), топ контейнеров по CPU/памяти (container-exporter поверх Docker Engine API — замена cAdvisor, несовместимого с containerd-снапшоттером сервера 1gb, см. .forcc/JOURNAL.md) и характеристики сервера — профиль 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": "Источник — container-exporter (job container-exporter, свой сервис поверх Docker Engine API, см. deploy/monitoring/container-exporter/). Отвечает на вопрос «кто из контейнеров грузит CPU» при срабатывании HostCpuHigh. % от одного ядра — как `docker stats`, суммарно может быть больше 100 при нескольких ядрах.",
|
||
"type": "timeseries",
|
||
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 20 },
|
||
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
||
"fieldConfig": {
|
||
"defaults": { "unit": "percent", "custom": { "drawStyle": "line", "fillOpacity": 10, "stacking": { "mode": "normal" } } },
|
||
"overrides": []
|
||
},
|
||
"targets": [
|
||
{
|
||
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
||
"expr": "topk(5, vidconf_container_cpu_percent)",
|
||
"legendFormat": "{{name}}",
|
||
"refId": "A"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": 11,
|
||
"title": "Топ контейнеров по памяти",
|
||
"description": "vidconf_container_memory_usage_bytes — usage без переиспользуемого page cache (working set), источник — container-exporter.",
|
||
"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, vidconf_container_memory_usage_bytes)",
|
||
"legendFormat": "{{name}}",
|
||
"refId": "A"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": 12,
|
||
"title": "Ядра CPU",
|
||
"description": "Число ядер хоста (node-exporter, живое значение — работает на любой инсталляции, не только на 1gb).",
|
||
"type": "stat",
|
||
"gridPos": { "h": 4, "w": 6, "x": 0, "y": 36 },
|
||
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
||
"fieldConfig": {
|
||
"defaults": {
|
||
"unit": "none",
|
||
"decimals": 0,
|
||
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] }
|
||
},
|
||
"overrides": []
|
||
},
|
||
"targets": [
|
||
{
|
||
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
||
"expr": "count(count by (cpu) (node_cpu_seconds_total{mode=\"idle\"}))",
|
||
"refId": "A"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": 13,
|
||
"title": "Объём RAM",
|
||
"description": "Полный объём памяти хоста (node-exporter, живое значение).",
|
||
"type": "stat",
|
||
"gridPos": { "h": 4, "w": 6, "x": 6, "y": 36 },
|
||
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
||
"fieldConfig": {
|
||
"defaults": {
|
||
"unit": "decbytes",
|
||
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] }
|
||
},
|
||
"overrides": []
|
||
},
|
||
"targets": [
|
||
{
|
||
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
||
"expr": "node_memory_MemTotal_bytes",
|
||
"refId": "A"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": 14,
|
||
"title": "Диск (/)",
|
||
"description": "Полный размер корневого раздела (node-exporter, живое значение) — не путать с панелью «Свободно на диске» выше (там остаток).",
|
||
"type": "stat",
|
||
"gridPos": { "h": 4, "w": 6, "x": 12, "y": 36 },
|
||
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
||
"fieldConfig": {
|
||
"defaults": {
|
||
"unit": "decbytes",
|
||
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] }
|
||
},
|
||
"overrides": []
|
||
},
|
||
"targets": [
|
||
{
|
||
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
||
"expr": "node_filesystem_size_bytes{mountpoint=\"/\",fstype!=\"tmpfs\"}",
|
||
"refId": "A"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": 15,
|
||
"title": "GPU",
|
||
"description": "Обнаруженная install.sh видеокарта (backend, gauge vidconf_host_info — HW_GPU_NAME из .env, ADR-004). «—» — видеокарты нет либо install.sh не запускался (dev-окружение). Таблица, а не stat-панель: у stat-панели в режиме отображения имени серии свой алгоритм автоподбора размера шрифта, который для однознаковых значений вроде «—» рисует нечитаемо мелкий текст.",
|
||
"type": "table",
|
||
"gridPos": { "h": 4, "w": 6, "x": 18, "y": 36 },
|
||
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
||
"fieldConfig": {
|
||
"defaults": { "custom": { "align": "center" } },
|
||
"overrides": []
|
||
},
|
||
"options": {
|
||
"showHeader": true,
|
||
"cellHeight": "lg"
|
||
},
|
||
"transformations": [
|
||
{
|
||
"id": "organize",
|
||
"options": {
|
||
"excludeByName": {
|
||
"Time": true,
|
||
"Value": true,
|
||
"__name__": true,
|
||
"cpus": true,
|
||
"ram_mb": true,
|
||
"instance": true,
|
||
"job": true
|
||
},
|
||
"renameByName": { "gpu_name": "Модель", "vram_mb": "VRAM, МБ" }
|
||
}
|
||
}
|
||
],
|
||
"targets": [
|
||
{
|
||
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
||
"expr": "vidconf_host_info",
|
||
"format": "table",
|
||
"instant": true,
|
||
"refId": "A"
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|