No description
Find a file
2025-11-24 11:29:12 +03:00
.github/workflows Add acceptance gates and diagnostics instrumentation 2025-11-24 11:28:52 +03:00
acceptance Add acceptance gates and diagnostics instrumentation 2025-11-24 11:28:52 +03:00
docs Add backend context scaffolding for UI 2025-11-23 23:10:47 +03:00
e2e Add acceptance gates and diagnostics instrumentation 2025-11-24 11:28:52 +03:00
profiles Add UI skeleton status and profiles 2025-11-22 15:13:17 +03:00
public Add comprehensive test harness with mocks and e2e 2025-11-24 11:08:00 +03:00
routers Fix caching, dedupe, and proxy handling 2025-11-22 15:35:19 +03:00
scripts Add task graph scaffolding and checklist 2025-11-24 10:34:41 +03:00
specs Add acceptance gates and diagnostics instrumentation 2025-11-24 11:28:52 +03:00
src Add acceptance gates and diagnostics instrumentation 2025-11-24 11:28:52 +03:00
tasks Add task graph scaffolding and checklist 2025-11-24 10:34:41 +03:00
test Add acceptance gates and diagnostics instrumentation 2025-11-24 11:28:52 +03:00
tests Add UI skeleton status and profiles 2025-11-22 15:13:17 +03:00
.env.example Add backend context scaffolding for UI 2025-11-23 23:10:47 +03:00
.gitignore Add IO layer scaffolding for cloudvisor UI 2025-11-23 23:50:32 +03:00
__init__.py Implement phase 0 sanitation and tracing 2025-11-22 13:20:13 +03:00
agg_catalog.py Add aggregation endpoints with caching and cost hints 2025-11-22 14:43:26 +03:00
api_metrics.py Implement performance reliability phase 2025-11-22 15:03:23 +03:00
cache.py Add managed Kubernetes and serverless profiles 2025-11-22 14:30:54 +03:00
cache_keys.py Add UI skeleton status and profiles 2025-11-22 15:13:17 +03:00
config.py Add UI skeleton status and profiles 2025-11-22 15:13:17 +03:00
errors.py Add UI skeleton status and profiles 2025-11-22 15:13:17 +03:00
hot_cache.py Fix caching, dedupe, and proxy handling 2025-11-22 15:35:19 +03:00
http.py Add UI skeleton status and profiles 2025-11-22 15:13:17 +03:00
http_utils.py Add UI skeleton status and profiles 2025-11-22 15:13:17 +03:00
index.html Add IO layer scaffolding for cloudvisor UI 2025-11-23 23:50:32 +03:00
inflight.py Fix caching, dedupe, and proxy handling 2025-11-22 15:35:19 +03:00
logging_config.py Implement phase 0 sanitation and tracing 2025-11-22 13:20:13 +03:00
main.py Fix caching, dedupe, and proxy handling 2025-11-22 15:35:19 +03:00
models.py Implement phase 0 sanitation and tracing 2025-11-22 13:20:13 +03:00
package-lock.json Add acceptance gates and diagnostics instrumentation 2025-11-24 11:28:52 +03:00
package.json Add acceptance gates and diagnostics instrumentation 2025-11-24 11:28:52 +03:00
playwright.config.ts Add comprehensive test harness with mocks and e2e 2025-11-24 11:08:00 +03:00
profile_schema.py Implement profile-based metrics phase 3 2025-11-22 13:58:46 +03:00
profiles.py Add UI skeleton status and profiles 2025-11-22 15:13:17 +03:00
profiles_catalog.py Fix caching, dedupe, and proxy handling 2025-11-22 15:35:19 +03:00
prom.py Fix caching, dedupe, and proxy handling 2025-11-22 15:35:19 +03:00
README.md Add acceptance gates and diagnostics instrumentation 2025-11-24 11:28:52 +03:00
requirements.txt Add managed Kubernetes and serverless profiles 2025-11-22 14:30:54 +03:00
schemas.py Add export matrix endpoint with streaming formats 2025-11-22 14:53:42 +03:00
tsconfig.json Add comprehensive test harness with mocks and e2e 2025-11-24 11:08:00 +03:00
vite.config.ts Add comprehensive test harness with mocks and e2e 2025-11-24 11:08:00 +03:00
warmup.py Implement performance reliability phase 2025-11-22 15:03:23 +03:00

🛰️ CloudVisor API

CloudVisor — это промежуточный API-слой между Prometheus-экспортером Yandex Cloud и пользовательским UI для визуализации метрик облачной инфраструктуры. Он объединяет несколько источников данных (Prometheus, Redis-кэш, Yandex Cloud Metrics API через экспортёр) и предоставляет единый удобный интерфейс для фронтенда и внешних интеграций.


🚀 Цель проекта

Создать модульную систему, аналогичную CloudAdvisor, но полностью на своей инфраструктуре. Функции:

  • централизованный доступ к метрикам Yandex Cloud (через Prometheus API);
  • унифицированные модели данных (vector, matrix);
  • адаптивное кэширование (Redis);
  • профили сервисов (Compute, ALB, PostgreSQL и др.);
  • REST API для визуализаций, аналитики и алертинга;
  • возможность добавлять новые типы профилей через YAML без изменения кода.

Всё это — бэкенд без UI, но готовый для подключения к любому фронту или Grafana-подобной системе.


⚙️ Архитектура

CloudVisor API общается с внешними контейнерами, которые уже запущены и предоставляют данные:

Контейнер Назначение Порт Описание
prometheus-yc-metrics-exporter Prometheus-совместный экспортёр для Yandex Cloud 9090 Запрашивает метрики у Yandex Monitoring API (prometheusMetrics)
yc-metrics-exporter Локальный Flask-сервис (NiceOS), агрегация метрик Yandex Cloud по папкам 9000 Источник метрик для Prometheus
niceos-redis Redis-кэш 6379 Используется CloudVisor API для кэширования ответов Prometheus

CloudVisor API работает поверх этой инфраструктуры как «умный прокси» и предоставляет:

  • /api/v1/vm/... — метрики виртуальных машин,
  • /api/v1/meta/... — служебные справочники (метки, серии, имена метрик),
  • /api/v1/profile/... — универсальные эндпоинты для разных сервисов на основе YAML-профилей.

🧩 Обзор фаз разработки

Фаза 0 — Базовая санитария

Цель: очистка и стандартизация. Сделано:

  • единые модели данных (MetricVectorResponse, MetricMatrixResponse);
  • удалены старые неиспользуемые импорты (prom_client);
  • добавлен trace_id для всех запросов и единый формат ошибок JSON;
  • улучшен /healthz: проверка Redis, Prometheus, экспортёра;
  • включено логирование и базовые тесты.

Результат: чистая кодовая база с прозрачными контрактами и трассировкой.


Фаза 1 — Контекст (что уже есть)

Настроена связь с существующим бэкендом CloudVisor API:

  • FastAPI на http://localhost:8000
  • Redis, Prometheus, Exporter в docker-окружении
  • UI получает /status и отображает ключевые параметры окружения.

Фаза 1 — Ядро Compute (VM)

Цель: реализовать API для работы с метриками виртуальных машин.

Добавлено:

  • /api/v1/vm/list — список всех ВМ, найденных в Prometheus;
  • /api/v1/vm/{id}/cpu/instant|range — загрузка CPU (момент и история);
  • /api/v1/vm/{id}/network/range — входящий/исходящий трафик с rate();
  • /api/v1/vm/{id}/overview — сводные метрики ВМ (CPU, сеть, память и др.);
  • /api/v1/summary/instant|range — агрегаты по всем ВМ;
  • кэш Redis с TTL, флагами X-From-Cache, X-Stale;
  • нормализация ответов Prometheus → структурированные JSON.

Результат: полноценный REST API для Compute-метрик, пригодный для UI-дашборда.


Фаза 2 — Meta-слой

Цель: справочная подсистема и introspection Prometheus.

Добавлено:

  • /api/v1/meta/metrics — список всех имён метрик;
  • /api/v1/meta/labels — список всех лейблов;
  • /api/v1/meta/label/{name}/values — возможные значения конкретной метки;
  • /api/v1/meta/series?match[]=... — time-series для заданных фильтров;
  • кэш Redis для всех мета-данных;
  • единая логика ошибок и trace_id.

Результат: фронтенд или аналитическая система может динамически строить запросы, зная, какие метки и метрики доступны.


Фаза 3 — Profiles

Цель: универсальный слой абстракции метрик.

Идея: описывать метрики сервисов в YAML-профилях (profiles/*), а API само подставляет PromQL и отдает нормализованные данные.

Реализовано:

  • формат профиля (entity, selector, defaults, metrics, groups);

  • пример профиля profiles/compute.yaml для ВМ и profiles/alb.yaml для ALB;

  • шаблонизация PromQL ({{id}}, {{range_window}});

  • трансформации (to_percent, scale);

  • эндпоинты:

    • /api/v1/profile/list — список профилей;
    • /api/v1/profile/{entity}/search — поиск сущностей (по метке);
    • /api/v1/profile/{entity}/{id}/overview — сводная метрика по группе;
    • /api/v1/profile/{entity}/{id}/metric/{name}/instant|range — отдельная метрика;
    • /api/v1/profile/_admin/reload — перезагрузка YAML без рестарта;
  • поддержка новых сервисов добавлением YAML без изменения кода.

Результат: универсальный API, где добавление нового сервиса (ALB, PostgreSQL, K8s, Redis, Storage и др.) — это просто новый профиль YAML.


🧠 Как это работает в рантайме

  1. Экспортёр (yc-metrics-exporter) запрашивает метрики у Yandex Monitoring API и отдает их в формате Prometheus.

  2. Prometheus (prometheus-yc-metrics-exporter) собирает эти метрики и хранит их во временной БД.

  3. CloudVisor API выполняет запросы к Prometheus через HTTP API:

    • преобразует данные в структурированный JSON (Pydantic);
    • кэширует ответы в Redis;
    • добавляет трассировку и метаданные;
    • агрегирует результаты по профилям и сервисам.
  4. Фронтенд (в будущем) обращается к CloudVisor API и получает готовые данные для визуализации.


🧰 Основные зависимости

  • FastAPI — фреймворк для API
  • httpx — асинхронный HTTP-клиент для Prometheus
  • redis.asyncio — кэш
  • pydantic / pydantic-settings — модели и конфиг
  • PyYAML — для загрузки профилей
  • pytest / httpx_mock — тестирование

🧪 Примеры запросов

# Проверить статус сервисов
curl http://localhost:8000/healthz

# Получить список ВМ
curl http://localhost:8000/api/v1/vm/list

# Моментальная загрузка CPU по ВМ
curl http://localhost:8000/api/v1/vm/vm-123/cpu/instant

# История CPU за час
curl "http://localhost:8000/api/v1/vm/vm-123/cpu/range?minutes=60&step_seconds=30"

# Сводные данные ВМ
curl http://localhost:8000/api/v1/vm/vm-123/overview

# Все метрики Prometheus
curl http://localhost:8000/api/v1/meta/metrics

# Все профили
curl http://localhost:8000/api/v1/profile/list

# Перезагрузить YAML-профили (dev)
curl -X POST -H "Authorization: Bearer <TOKEN>" http://localhost:8000/api/v1/profile/_admin/reload

📜 Контракты UI ↔ API

Фронтенд (cloudvisor-ui) использует строгие типы ответов и единый парсер ошибок, чтобы гарантировать стабильные интеграции:

  • ApiError описывает коды и трассировку ошибок бэкенда; клиент бросает этот тип при любых не-2xx ответах и сохраняет trace_id.
  • Все запросы читают метаданные кэша (X-From-Cache, X-Stale, X-Cache-Layer) и отображают их бейджами в UI и dev-оверлее.
  • DTO для ключевых ручек (/status, /api/v1/meta/metrics, /api/v1/profile/...) описаны в src/types/apiContracts.ts и используются в React Query хукаx.
  • Тесты (src/__tests__/contracts.spec.ts) проверяют корректность парсинга ошибок и fallback для невалидного JSON.

⚙️ Конфигурация UI

Укажите базовый URL API через переменную окружения Vite:

VITE_CLOUDVISOR_API_BASE=http://localhost:8000

Граф задач (исполнение)

  • Исходный план: tasks/PLAN.yml
  • Генерация тикетов: npm run gen:tasks → создаёт tasks/*/*.md
  • Скафолдинг кода под тикет: npm run scaffold <TASK_ID>
  • Быстрые проверки UI: страница /checklist (ссылки на ключевые страницы)
  • DoD checklist: tasks/TEMPLATE_DOD.md + раздел Acceptance в каждом тикете

Definition of Done (приёмка)

  • Функционал: покрыты 7 сценариев; UI живёт при падении Prometheus (stale).
  • Скорость: p95 рендера Overview/Top ≤ 500 мс (прогретый API).
  • Достоверность: матрицы совпадают с /api/v1/query_range (|Δ| ≤ 1e-6/точку).
  • Экспорт: CSV-wide детерминированный; 1ч/30с/≤50 рядов — ≤ 3 с.
  • Диагностика: страница показывает p95/p99, hits, stale share; trace_id в UI.
  • UX: i18n (ru/en), A11y ≥95 (axe-smoke без нарушений), понятные ошибки/лоадеры.
  • Код: линт/тесты/билд — зелёные; VITE_CLOUDVISOR_API_BASE настраивает окружение.

📚 Документация профилей

Список доступных профилей и расшифровка KPI лежат в каталоге profiles/docs. Там описаны варианты метрик для managed-баз данных (PostgreSQL, MySQL, Redis, MongoDB, ClickHouse, Kafka) и состав групп overview.


🧩 Что будет дальше

После трёх фаз CloudVisor API готов стать ядром визуальной системы. Следующие шаги:

  • добавить UI (React/Vue + ECharts или Plotly);
  • построить ролевую модель и аутентификацию;
  • интегрировать алерты и SLA-анализ;
  • добавить профили для всех Yandex Cloud сервисов: profiles/postgresql.yaml, profiles/redis.yaml, profiles/loadbalancer.yaml, profiles/ydb.yaml, profiles/s3.yaml и др.

🔍 Итоговая цель

CloudVisor превращает «сырые» метрики Prometheus/Yandex Cloud в единое API-описание состояния инфраструктуры, понятное как для графиков, так и для аналитики. Он даёт гибкость PromQL, но скрывает её сложность за YAML-профилями, кэшем и нормализацией данных.


🧱 Мини-архитектура (TL;DR)

[Yandex Cloud Monitoring]
        ↓
 [yc-metrics-exporter:9000]
        ↓
 [Prometheus:9090]
        ↓
 [CloudVisor API (FastAPI)]
        ↓
 [Redis Cache:6379]
        ↓
 [Frontend or Analytics Tools]

Проект создаёт основу для собственного CloudAdvisor-подобного инструмента мониторинга, но полностью управляемого и расширяемого в рамках NiceOS-экосистемы.


ниже — «расширенная анатомия» экспортёра NiceOS для Yandex Cloud: что он именно отдаёт, какие гарантии даёт, как устроены метки/формат, как его скрейпит Prometheus, где кэш, какие права нужны, как он ведёт себя при сбоях, и как CloudVisor API это потребляет. Это — дополнение к README и базовой архитектуре.


Что именно мы получаем от экспортёра

1) Что делает экспортёр по факту

  • Достаёт метрики из Yandex Monitoring prometheusMetrics (REST) по каждому сервису и каждой папке (folder) согласно выбранному режиму (одна папка / список / автодискавери по облаку).

  • Склеивает все ответы в единый Prometheus-совместимый текст.

  • Чистит дубли # HELP/# TYPE при мультипапочном сборе — чтобы Prometheus не ругался.

  • Выдаёт две основные точки:

    • GET /metrics/all — «всё-по-всем»;
    • GET /metrics/<service> — только один сервис (по всем папкам).
  • Обновляет список папок в фоне (lenient авто-рефреш).

  • Имеет /healthz для быстрой диагностики (включаем «глубокую» проверку Monitoring API через HEALTH_CHECK_DEEP=true).

На практике это — универсальный Prometheus target, который маскирует сложность Yandex API (IAM, постраничность, выбор папок/сервисов, нормализация).


2) Какой именно формат на выходе

Экспортёр отдаёт чистый Prometheus exposition format, готовый к скрейпу. Пример (условный):

# HELP cpu_usage CPU utilization ratio (0..1)
# TYPE cpu_usage gauge
cpu_usage{resource_type="vm",resource_id="vm-123",folder_id="b1f...",job="yc",instance="monitoring.api.cloud.yandex.net"} 0.27 1732259700000
cpu_usage{resource_type="vm",resource_id="vm-456",folder_id="b1f...",job="yc",instance="monitoring.api.cloud.yandex.net"} 0.43 1732259700000

# HELP network_received_bytes_total Total bytes received
# TYPE network_received_bytes_total counter
network_received_bytes_total{resource_type="vm",resource_id="vm-123",nic="eth0",folder_id="b1f..."} 1.8243e+09 1732259700000
...

Особенности:

  • Метки (labels) формируются так, чтобы не терялась принадлежность:

    • минимум: __name__, resource_type, resource_id, folder_id;
    • часто: job, instance (источник), плюс доменные (nic, device, code, alb_id, bucket и т.п.).
  • Временные метки — в миллисекундах (как в стандартном экспозиционном тексте).

  • Счётчики (*_total) и gauge-метрики — в нативных единицах:

    • cpu_usage — как правило, ratio (0..1);
    • сетевые/дисковые байты — накопительные (*_bytes_total), для скорости используем rate() в PromQL;
    • latency — или как гистограмма (*_bucket), или как агрегаты (зависит от сервиса).

3) Что «гарантируется» экспортёром

  • Единый формат и дедуп служебных строк HELP/TYPE при объединении множества папок.

  • Стабильная маршрутизация сервисов: список по умолчанию DEFAULT_SERVICES покрывает официальные сервисы Monitoring + managed-elasticsearch (legacy).

  • Кэширование на стороне экспортёра:

    • кэширует собранный сырой Prometheus-текст (TTL CACHE_DEFAULT_TIMEOUT, по умолчанию 300 с);
    • экономит лимиты Monitoring API и сглаживает пики скрейпа.
  • Ленивая автоактуализация папок (интервал FOLDER_REFRESH_INTERVAL, по умолчанию 600 с) с защитой от «дупликата» запросов.


4) Потоки данных и где кэш

[Yandex Monitoring prometheusMetrics]
           ↑  (IAM, per-folder, per-service)
           │
       [Экспортёр]
       - /metrics/all
       - /metrics/<service>
           │  (Prometheus exposition text)
           ↓
        [Prometheus]
           │  (HTTP scrape)
           ↓
     [CloudVisor API]
     - PromQL (HTTP API Prometheus)
     - Redis кэш (JSON)
  • Экспортёр кэширует сырой текст /metrics/*.
  • Prometheus уже держит у себя временной ряд (TSDB).
  • CloudVisor API поверх Prometheus отдаёт нормализованный JSON (vector/matrix) с Redis-кэшем на ответы.

5) Как конфигурируется сбор

Режим выбора папок

  • Одна папка: YC_FOLDER_ID
  • Список: YC_FOLDER_IDS=b1f...,b1f...,b1f...
  • Автодискавери по облаку: YC_CLOUD_ID Экспортёр запросит Resource Manager GET /resource-manager/v1/folders?cloudId=... со страницами и соберёт id всех папок.

Какие сервисы тянуть

  • По умолчанию — DEFAULT_SERVICES (полный перечень из Monitoring).
  • Ограничить: YC_SERVICES=compute,application-load-balancer,storage (CSV).

Тайминги

  • REQUEST_TIMEOUT (по умолчанию 10 с) — HTTP таймаут к Yandex API.
  • CACHE_DEFAULT_TIMEOUT (по умолчанию 300 с) — кэш ответов /metrics/*.
  • FOLDER_REFRESH_INTERVAL (по умолчанию 600 с) — рефреш папок.

IAM-права

  • На prometheusMetrics — роль уровня monitoring.viewer (или шире).
  • Для авто-дискавери — resource-manager.viewer (или любая дающая folders.list по облаку).

6) Пример конфигурации Prometheus

scrape_configs:
  - job_name: 'yc-all'
    metrics_path: /metrics/all
    static_configs:
      - targets: ['yc-metrics-exporter:9000']

  - job_name: 'yc-compute'
    metrics_path: /metrics/compute
    static_configs:
      - targets: ['yc-metrics-exporter:9000']

  # Можно заводить отдельные джобы per service для гранулированных ретеншнов/прав/квот
  • Для крупной инсталляции разумно делить jobы по сервисам, чтобы контролировать частоту скрейпа и хранение.

7) Поведение при сбоях и деградациях

Ситуация Что делает экспортёр Что увидит Prometheus Что потом увидит CloudVisor
Monitoring API недоступен Возвращает пустой текст или частичный набор; пишет в логи Серия/метрики пропадут до восстановления В API появятся «дыры» в рядах; Redis отдаст прошлые ответы (если есть), CloudVisor может пометить X-Stale:true
Нет прав IAM /healthz вернёт ошибку конфигурации; /metrics/* будет почти пустым Метрик нет API вернёт пустые result/ошибку, подсветит проблему в логе
Автодискавери не сработал Падает на старте или остаётся со старым списком Скрейп идёт по «старому» набору Видим ограниченный набор сущностей до исправления
Медленный Monitoring API Упрётся в REQUEST_TIMEOUT Scrape может быть частично пустым Лучше поднять TTL кэша на экспортёре и/или снизить частоту скрейпа

Рекомендации:

  • при нестабильной сети увеличить CACHE_DEFAULT_TIMEOUT и/или уменьшить scrape_interval в Prometheus;
  • иметь отдельный дашборд на /healthz экспортёра и логах.

8) Набор сервисов и примеры метрик

Экспортёр поддерживает официальный список DEFAULT_SERVICES (Compute, ALB/NLB, Storage, Managed DB и т.д.). Примеры:

  • Compute (ВМ)

    • cpu_usage (gauge, 0..1)
    • network_received_bytes_total, network_sent_bytes_total (counter)
    • disk_read_bytes_total, disk_written_bytes_total (counter)
    • возможны memory_* (зависит от источника)
  • ALB/NLB

    • alb_http_requests_total, alb_http_responses_total{code}
    • http_request_duration_seconds_bucket (гистограмма)
    • nlb_bytes_total / nlb_packets_total (варианты)
  • Managed PostgreSQL / MySQL / Redis / MongoDB / ClickHouse / Kafka

    • QPS, connections, replication lag, bytes/ops per second (через rate()), гистограммы latency — зависят от сервиса.
  • Object Storage (S3)

    • запросы, коды ответов, трафик (вход/выход), latency (гистограмма при наличии).

Важно: точные имена метрик и лейблов определяет Monitoring для каждого сервиса. Экспортёр не переименовывает метрики — он транзитно их отдаёт (с нормализацией HELP/TYPE). Визуализация и агрегаты делаются на этапе PromQL (в Prometheus/CloudVisor API).


9) Как этим пользуется CloudVisor API

CloudVisor не скрейпит напрямую Monitoring. Он обращается к Prometheus, который уже «съел» экспортёр:

  • для «моментальных» значений → /api/v1/query → нормализуем в vector;
  • для «диапазона» → /api/v1/query_rangematrix;
  • для сетевых/дисковых счётчиков → всегда rate([5m]);
  • для latency гистограмм → histogram_quantile(0.95, sum by (le)(rate(bucket[5m]))).

CloudVisor поверх этого даёт:

  • VM-ручки (/api/v1/vm/...) — CPU/NET/MEM/DISK по resource_id;
  • Meta-ручки (/api/v1/meta/...) — список метрик, меток, серий;
  • Profiles (/api/v1/profile/...) — YAML-редактуруемые наборы KPI для любых сервисов.

10) Производительность и объём

  • CACHE_DEFAULT_TIMEOUT на экспортёре (300 с по дефолту) критично снижает нагрузку на Yandex API — каждый запрос /metrics/* не «бьёт» облако, если есть кэш.
  • Prometheus TSDB хранит историю и обеспечивает быстрый query_range.
  • CloudVisor кэширует уже нормализованный JSON в Redis (короткие TTL 1060 с), чтобы не повторять одно и то же PromQL.

Для больших инсталляций:

  • разбивайте /metrics/<service> на несколько jobs и снижайте частоту на тяжёлых сервисах;
  • используйте scrape_timeout < REQUEST_TIMEOUT экспортёра, чтобы не создавать «кластер» висящих запросов.

11) Безопасность и доступ

  • Экспортёр сам не требует аутентификации (это — внутренний сервис), но IAM токен обязателен на старте (YC_TOKEN).

  • CloudVisor (позже) прикрывается OIDC/Reverse Proxy (в нашей фазе — без ACL).

  • Внешние порты:

    • экспортёр: 9000 (/metrics/..., /healthz);
    • Prometheus: 9090 (HTTP API + scrape);
    • Redis: 6379.

docker ps у тебя уже показывает:

6a410b5b7afd  niceos/prometheus-yc-metrics-exporter:3.7.3  0.0.0.0:9090->9090  prometheus-yc-metrics-exporter
28fd9a41d2ee  niceos/redis:8.2.1                           0.0.0.0:6379->6379  niceos-redis
1b7081f15b62  niceos/nicesoft-yc-metrics-exporter:0.1.0    0.0.0.0:9000->9000  yc-metrics-exporter

— этого достаточно, чтобы CloudVisor API «наехал» поверх и начал давать JSON.


12) Трюки и практичные PromQL-«рецепты»

  • Скорость сети ВМ, байты/с:

    rate(network_received_bytes_total{resource_type="vm",resource_id="VM"}[5m])
    rate(network_sent_bytes_total{resource_type="vm",resource_id="VM"}[5m])
    
  • CPU как %:

    100 * cpu_usage{resource_type="vm",resource_id="VM"}
    
  • P95 по гистограммам:

    histogram_quantile(0.95, sum by (le)(
      rate(http_request_duration_seconds_bucket{service="alb"}[5m])
    ))
    
  • Топ-10 ВМ по трафику:

    topk(10, sum by (resource_id)(
      rate(network_received_bytes_total{resource_type="vm"}[5m]) +
      rate(network_sent_bytes_total{resource_type="vm"}[5m])
    ))
    

13) Траблшутинг экспортёра

  • /healthz:

    • status=error + reason=YC_TOKEN is not set → не задан IAM.
    • folder discovery failed → нет прав resource-manager.viewer или неверный YC_CLOUD_ID.
    • Включите HEALTH_CHECK_DEEP=true — проверит реальный вызов Monitoring API.
  • Логи при старте:

    • печатают фактический MONITORING_ENDPOINT, RESOURCE_MANAGER_ENDPOINT, количество папок, список сервисов и TTL.
    • проверяйте «пустые» ответы по сервисам — это не всегда ошибка, иногда действительно нет метрик.
  • Если Prometheus жалуется на HELP/TYPE дубли — проверьте, что вы обращаетесь к экспортёру, а не напрямую к Monitoring для каждой папки в разных таргетах (экспортёр уже решает проблему дубликатов).


14) Что это даёт CloudVisor целиком

  • Единая точка входа к метрикам Yandex Cloud, независимо от числа папок и сервисов.
  • Стабильная таксономия: понятные метки (resource_id, folder_id, …), к которым можно писать профили.
  • Снижение нагрузки на Monitoring API и Prometheus за счёт двухуровневого кэширования.
  • Быстрый путь к UI: CloudVisor API отдаёт чистые vector/matrix, фронт рисует графики без «запаха» PromQL.
  • Расширяемость: новый сервис → добавили YAML-профиль, UI уже умеет его читать.

коротко: экспортёр делает «грязную работу» общения с Yandex Monitoring и выдаёт чистые, консистентные, склеенные метрики для Prometheus. Дальше CloudVisor превращает их в быстрый, аккуратный JSON для любого клиента — от пользовательской панели до внешней аналитики.


CloudVisor API

CloudVisor — это API-слой над Prometheus, который нормализует метрики Yandex Cloud и отдаёт их в удобных JSON-структурах. Он строится поверх экспортёра NiceOS и Prometheus, использует Redis для кэша и поддерживает YAML-профили сервисов (Compute, ALB, DB и т.д.) — чтобы добавлять покрытие без изменения кода.


Зачем это нужно

  • Единый интерфейс ко всем метрикам облака, независимо от количества папок и сервисов.
  • Удобный формат: JSON vector/matrix вместо сырого Prometheus текста.
  • Быстрый отклик: кэш Redis на ответы API + кэш экспортёра на склейку metics.
  • Расширяемость через YAML: новые сервисы и KPI подключаются профилями, а не кодом.
  • Надёжность: чёткие таймауты/ретраи, health-checks, trace-id, деградация с stale кэшем.

Что уже крутится (контейнеры)

Из docker ps:

CONTAINER ID   IMAGE                                         PORTS                    NAMES
6a410b5b7afd   niceos/prometheus-yc-metrics-exporter:3.7.3   0.0.0.0:9090->9090/tcp   prometheus-yc-metrics-exporter
28fd9a41d2ee   niceos/redis:8.2.1                            0.0.0.0:6379->6379/tcp   niceos-redis
1b7081f15b62   niceos/nicesoft-yc-metrics-exporter:0.1.0     0.0.0.0:9000->9000/tcp   yc-metrics-exporter
  • yc-metrics-exporter:9000 — Flask-экспортёр, тянет prometheusMetrics из Yandex Monitoring и отдаёт готовый Prometheus exposition text:

    • GET /metrics/all — все сервисы по всем папкам,
    • GET /metrics/<service> — один сервис по всем папкам,
    • GET /healthz — статус токена/дискавери/доступности Monitoring API. Права: monitoring.viewer и (для автодискавери) resource-manager.viewer.
  • prometheus-yc-metrics-exporter:9090 — Prometheus, скрейпит экспортёр и хранит ряды.

  • niceos-redis:6379 — Redis-кэш для ответов CloudVisor API.

CloudVisor API разворачивается отдельно и подключается к этим сервисам.


Как это работает (потоки)

Yandex Monitoring (prometheusMetrics)
            ↑  (IAM, per folder, per service)
       yc-metrics-exporter:9000  →  Prometheus exposition text
            ↓ (scrape)
  prometheus-yc-metrics-exporter:9090
            ↓ (PromQL HTTP API)
          CloudVisor API
            ↓
          Redis (кэш JSON)
            ↓
        Фронт/интеграции
  • Экспортёр агрегирует запросы к Monitoring API, чистит дубли # HELP/TYPE, кэширует сырой текст (CACHE_DEFAULT_TIMEOUT).
  • Prometheus скрейпит экспортёр и даёт быстрый query/query_range.
  • CloudVisor API делает PromQL-запросы, нормализует в vector/matrix, кэширует JSON в Redis (короткие TTL), добавляет трассировку/заголовки.

Поверхностный API (после первых фаз)

  • VM (Compute): GET /api/v1/vm/list GET /api/v1/vm/{id}/cpu/instant|range GET /api/v1/vm/{id}/network/range (через rate()) GET /api/v1/vm/{id}/overview

  • Summary: GET /api/v1/summary/instant|range (суммарные CPU, RX/TX и др.)

  • Meta: GET /api/v1/meta/metrics — список имён метрик GET /api/v1/meta/labels — список лейблов GET /api/v1/meta/label/{name}/values GET /api/v1/meta/series?match[]=...

  • Profiles (YAML): GET /api/v1/profile/list GET /api/v1/profile/{entity}/search GET /api/v1/profile/{entity}/{id}/overview GET /api/v1/profile/{entity}/{id}/metric/{name}/instant|range POST /api/v1/profile/_admin/reload (dev)


Форматы ответов

// Vector
{
  "result_type": "vector",
  "result": [
    { "metric": {"resource_id":"vm-1", "...":"..."}, "value": {"timestamp": 1732262400.0, "value": 0.37} }
  ]
}

// Matrix
{
  "result_type": "matrix",
  "result": [
    {
      "metric": {"resource_id":"vm-1", "...":"..."},
      "values": [
        {"timestamp": 1732261800.0, "value": 0.23},
        {"timestamp": 1732261830.0, "value": 0.25}
      ]
    }
  ]
}
  • timestamp — сек (float).
  • Счётчики (*_total) — всегда через rate([5m]) → «в секунду».
  • CPU/Memory — gauge (при необходимости преобразуем ratio→percent).
  • Заголовки: X-Trace-Id, X-From-Cache, X-Stale.

Фазы и результаты

Ниже — полный план развития, что делаем на каждой фазе и что появляется.

Фаза 0 — Санитария и выравнивание базы

Задачи

  • Почистить рудименты (убрать prom_client, привести роутеры к единому PrometheusClient).
  • Единые модели: MetricVectorResponse, MetricMatrixResponse, нормализация from_prom_*.
  • Мидлвар трассировки: X-Trace-Id в каждом ответе.
  • Единый формат ошибок JSON: {error, message, trace_id}.
  • /healthz: проверка Redis, Prometheus, экспортёра (опционально), статус ok/degraded/error.
  • OpenAPI описания, валидация query-параметров.

Результат

  • Чистая, трассируемая база, пригодная для наращивания.

Фаза 1 — Ядро Compute (ВМ)

Задачи

  • Ручки для ВМ:

    • /api/v1/vm/list
    • /api/v1/vm/{id}/cpu/instant|range
    • /api/v1/vm/{id}/network/range (RX/TX bps через rate())
    • /api/v1/vm/{id}/overview
  • Summary:

    • /api/v1/summary/instant|range (sum cpu / net bps)
  • Redis-кэш: короткие TTL (instant 1015с, range/overview 1560с), заголовки X-From-Cache, X-Stale.

  • Обработка таймаутов/ошибок Prometheus (504/502).

Результат

  • Полноценный API для Compute метрик — готовая основа для дашборда.

Фаза 2 — Meta-слой

Задачи

  • /api/v1/meta/metrics — имена метрик (/__name__/values)
  • /api/v1/meta/labels — ключи лейблов
  • /api/v1/meta/label/{name}/values — значения лейбла
  • /api/v1/meta/series?match[]=... — time-series по match[] Все с Redis-кэшем (25 минут) и fallback на stale.

Результат

  • Интроспекция и справочники для фронта/аналитики.

Фаза 3 — Профили (profiles/*)

Задачи

  • YAML-схема профиля: entity, selector, defaults, metrics, groups.
  • Шаблоны PromQL ({{id}}, {{range_window}}) + трансформации (to_percent, scale).
  • Роутеры profile/*: list, search, {id}/overview, {id}/metric/{name}/instant|range.
  • Горячая перезагрузка профилей (dev): POST /profile/_admin/reload.

Результат

  • Универсальный слой: новые сервисы добавляются YAML-файлом.
  • Готовые профили: compute.yaml (vm), alb.yaml и др.

Фаза 4 — Покрытие сервисов (волна 1)

Задачи

  • Профили:

    • compute.yaml — CPU, memory, net, disk
    • application-load-balancer.yaml — RPS, 5xx, p95 latency
    • network-load-balancer.yaml — bytes/packets, errors
    • storage.yaml (S3) — rps, bytes, errors, latency
  • groups.overview для каждого.

Результат

  • Полное покрытие базовой инфраструктуры.

Фаза 5 — Managed Databases (волна 2)

Задачи

  • Профили: managed-postgresql.yaml, managed-mysql.yaml, managed-redis.yaml, managed-mongodb.yaml, managed-clickhouse.yaml, managed-kafka.yaml.
  • KPI: QPS/OPS, connections, replication lag, memory/storage usage, latency quantiles (если есть bucket).

Результат

  • Покрытие управляемых БД и брокеров.

Фаза 6 — Kubernetes/Serverless

Задачи

  • managed-kubernetes.yaml: node cpu/mem, pod counts, restarts, evictions, API server requests.
  • serverless-functions.yaml / serverless-containers.yaml / serverless-apigateway.yaml: invocations, errors, duration p95, throttles.

Результат

  • Набор профилей для контейнерной и безсерверной нагрузки.

Фаза 7 — Агрегаты

Задачи

  • /api/v1/agg/{domain}/top?metric=&order=&limit=&minutes= Топ-N сущностей по KPI (например, топ ВМ по трафику).
  • /api/v1/agg/cost-hints (черновик) — агрегаты, близкие к стоимости.

Результат

  • Готовые «сводки» без сложного PromQL на клиенте.

Фаза 8 — Экспорт

Задачи

  • POST /api/v1/export/matrix — NDJSON/CSV/Parquet выгрузка диапазонов.
  • Лимиты по окну/рядам, стриминг, лог сигнатур запросов.

Результат

  • Удобный оффлайн-экспорт для анализа.

Фаза 9 — Производительность/Надёжность

Задачи

  • In-memory LRU поверх Redis, объединение in-flight запросов.
  • Настройки таймаутов/ретраев/keep-alive.
  • Прогрев «summary/overview» кэшей.
  • Метрики самого API: /metrics (Prometheus формат) — latency, cache hits, backend errors.

Результат

  • Малые задержки, предсказуемость, наблюдаемость API.

Фаза 10 — Безопасность

Задачи

  • OIDC/OAuth2 за reverse-proxy.
  • RBAC по профилям и папкам.
  • Rate limiting и аудит.

Результат

  • Готовность к production-экспозиции.

Фаза 11 — Документация и SDK

Задачи

  • Детальные docs по профилям и PromQL-cookbook.
  • TypeScript SDK из OpenAPI.
  • Примеры Grafana dashboards на CloudVisor API.

Результат

  • Проект «самообъясняется» и легко внедряется.

Фаза 12 — Готовность к UI

Задачи

  • Убедиться, что overview/top/meta/export закрывают сценарии интерфейса.
  • /status с версиями: api_version, profiles_revision, prometheus_url.

Результат

  • Безболезненная интеграция любого UI.

Конфигурация CloudVisor API

Переменные окружения (минимум):

CLOUDVISOR_PROM_URL=http://prometheus-yc-metrics-exporter:9090
CLOUDVISOR_REDIS_URL=redis://niceos-redis:6379/0
CLOUDVISOR_ALLOWED_ORIGINS_RAW=*
CLOUDVISOR_REQUEST_TIMEOUT_SECONDS=5.0
CLOUDVISOR_CACHE_TTL_SECONDS=30
PROFILE_DIR=./profiles

Для dev:

PROFILE_RELOAD_ENABLED=true
PROFILE_RELOAD_TOKEN=<secret>

Типовые PromQL-рецепты (в API применяются автоматически)

  • Сеть (байты/с): rate(network_received_bytes_total{...}[5m]) rate(network_sent_bytes_total{...}[5m])

  • CPU (%): 100 * cpu_usage{...} (если метрика ratio)

  • Диск (байты/с по устройствам): sum by (device)(rate(disk_read_bytes_total{...}[5m])) sum by (device)(rate(disk_written_bytes_total{...}[5m]))

  • Latency p95: histogram_quantile(0.95, sum by (le)(rate(http_request_duration_seconds_bucket{...}[5m])))


Примеры запросов

# Здоровье
curl http://localhost:8000/healthz

# Compute: список ВМ
curl http://localhost:8000/api/v1/vm/list

# CPU текущий/история
curl http://localhost:8000/api/v1/vm/vm-123/cpu/instant
curl "http://localhost:8000/api/v1/vm/vm-123/cpu/range?minutes=60&step_seconds=30"

# Сеть
curl "http://localhost:8000/api/v1/vm/vm-123/network/range?minutes=60&step_seconds=30"

# Сводка
curl http://localhost:8000/api/v1/summary/instant
curl "http://localhost:8000/api/v1/summary/range?minutes=60&step_seconds=30"

# Meta
curl http://localhost:8000/api/v1/meta/metrics
curl http://localhost:8000/api/v1/meta/labels
curl http://localhost:8000/api/v1/meta/label/resource_id/values
curl "http://localhost:8000/api/v1/meta/series?match[]=cpu_usage{resource_type=\"vm\"}"

# Profiles
curl http://localhost:8000/api/v1/profile/list
curl "http://localhost:8000/api/v1/profile/vm/vm-123/overview?minutes=60&step_seconds=30"
curl http://localhost:8000/api/v1/profile/vm/vm-123/metric/cpu_usage/instant

Нефункциональные требования (в UI)

  • Скорость: p95 рендера Overview/Top ≤ 500 мс при тёплом кэше.
  • Стабильность: при X-Stale:true UI не падает, помечает данные stale.
  • TTL (React Query staleTime):
    • meta: 120300 s
    • overview/range: 1530 s
    • instant: 1015 s
    • agg: 3060 s
  • Отмена/таймауты: AbortController + общий timeout 5s.
  • Повторы: до 2, без 4xx, с backoff+jitter.
  • Безопасность: без секретов, никакого raw HTML, логирование без шума.
  • Диагностика: страница Diagnostics показывает p50/p95 рендера, cache hits/stale из /metrics.

Ошибки и заголовки

  • Любой ответ содержит X-Trace-Id.
  • Кэш: X-From-Cache: true|false, устаревший кэш: X-Stale: true|false.
  • Ошибки — JSON:
{ "error": "prometheus_timeout", "message": "upstream timeout after 5.0s", "trace_id": "..." }

Что получаем в итоге

  • Универсальный API мониторинга поверх Yandex Cloud, без жёсткой привязки к конкретному UI.
  • Гибкость PromQL остаётся, но скрыта в YAML-профилях; расширять можно без релиза кода.
  • Производительность за счёт двух уровней кэша (экспортёр и Redis), аккуратных TTL и объединения запросов.
  • Надёжность через health-checks, единый формат ошибок, трассировку запросов и метрики самого API.
  • Масштабируемость: новые сервисы покрываются профилями (profiles/*) — Compute, LB, Storage, Managed DB, Kubernetes, Serverless и т.д.

TL;DR: CloudVisor превращает «сырые» прометеевские ряды Yandex Cloud в стабильный, быстрый и расширяемый JSON-API, готовый для панелей, алертов и интеграций.