Вопрос 24 · Раздел 14

Как мониторить приложения в Kubernetes?

Мониторинг — это приборная панель автомобиля. Спидометр показывает скорость (CPU usage), датчик температуры — перегрев (memory usage), лампочка CHECK ENGINE — что-то сломалось (...

Версии по языкам: English Russian Ukrainian

🟢 Junior Level

Простое определение

Мониторинг в Kubernetes — это практика сбора, хранения и анализа данных о состоянии кластера, контейнеров и приложений. Мониторинг отвечает на три вопроса: “Что происходит?”, “Почему это произошло?” и “Как это предотвратить?”

Аналогия

Мониторинг — это приборная панель автомобиля. Спидометр показывает скорость (CPU usage), датчик температуры — перегрев (memory usage), лампочка CHECK ENGINE — что-то сломалось (error rate). Без приборной панели вы едете вслепую.

Пример: Установка Prometheus Stack (Helm)

# Добавить репозиторий
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update

# Установить kube-prometheus-stack
helm install monitoring prometheus-community/kube-prometheus-stack \
  --namespace monitoring --create-namespace

Пример: Spring Boot Actuator + Micrometer

<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
# application.yml
management:
  endpoints:
    web:
      exposure:
        include: health,info,prometheus
  metrics:
    export:
      prometheus:
        enabled: true

Пример kubectl

# Открыть Grafana dashboard
kubectl port-forward svc/monitoring-grafana 3000:80 -n monitoring
# http://localhost:3000 (admin/prom-operator)

# Открыть Prometheus UI
kubectl port-forward svc/monitoring-prometheus 9090:9090 -n monitoring

# Посмотреть Pod'ы мониторинга
kubectl get pods -n monitoring
# prometheus-monitoring-0
# grafana-xxxxx
# alertmanager-monitoring-0

Когда использовать

  • Всегда в production — без мониторинга вы слепы
  • Для отслеживания CPU, memory, disk, network usage
  • Для обнаружения ошибок и деградации производительности
  • Для алертинга: SMS/email/Slack при проблемах

🟡 Middle Level

Как это работает

Мониторинг в Kubernetes строится на четырёх компонентах:

  1. Prometheus — time-series database, собирает метрики методом pull (опрашивает эндпоинты каждые 15-30 секунд)

Prometheus – де-факто стандарт мониторинга в K8s. Pull-модель: Prometheus сам забирает метрики с Pod’ов через HTTP endpoint (/metrics).

  1. Node Exporter — DaemonSet на каждой ноде, собирает метрики ОС (CPU, RAM, disk, network)
  2. cAdvisor — встроен в kubelet, собирает метрики контейнеров (CPU, memory, network per container)
  3. kube-state-metrics — Deployment, генерирует метрики о K8s объектах (Pod status, Deployment replicas, PVC usage)
  4. Grafana — визуализация, дашборды, алертинг

Цепочка сбора метрик:

App (/actuator/prometheus) ← Prometheus scrapes every 15s
Node Exporter ( DaemonSet) ← Prometheus scrapes every 15s
cAdvisor (kubelet)         ← Prometheus scrapes every 15s
kube-state-metrics         ← Prometheus scrapes every 15s
                              ↓
                          Prometheus TSDB (хранит 15 дней)
                              ↓
                          Grafana (дашборды)
                              ↓
                          Alertmanager (уведомления)

Практические сценарии

Сценарий 1: Мониторинг Java-приложения

# JVM memory usage
jvm_memory_used_bytes{area="heap"}

# GC pause time
rate(jvm_gc_pause_seconds_sum[5m])

# HTTP request rate
rate(http_server_requests_seconds_count[5m])

# HTTP error rate (5xx)
rate(http_server_requests_seconds_count{status=~"5.."}[5m])

# Request latency p99
histogram_quantile(0.99, rate(http_server_requests_seconds_bucket[5m]))

Сценарий 2: Алерт на рост 5xx ошибок

# PrometheusRule
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: app-alerts
spec:
  groups:
    - name: app.rules
      rules:
        - alert: HighErrorRate
          expr: |
            sum(rate(http_server_requests_seconds_count{status=~"5.."}[5m]))
            / sum(rate(http_server_requests_seconds_count[5m])) > 0.05
          for: 5m
          labels:
            severity: critical
          annotations:
            summary: "5xx error rate > 5% for 5 minutes"

Сценарий 3: Логирование через Loki

# Helm values для Loki
loki:
  commonConfig:
    replication_factor: 1
  storage:
    type: filesystem

promtail:
  enabled: true

Promtail (DaemonSet) собирает логи с каждой ноды → отправляет в Loki → Grafana визуализирует.

Таблица распространённых ошибок

Ошибка Последствие Решение
Только инфраструктурные метрики, без бизнес-метрик Видно, что CPU в норме, но не видно, что платежи не проходят Добавлять business metrics: payments_per_second, order_processing_time
Prometheus хранит метрики только 15 дней Невозможно проанализировать долгосрочные тренды Использовать Thanos/Cortex для долгосрочного хранения (S3)
Слишком много алертов (alert fatigue) Команда игнорирует алерты, пропускает критичные Сократить до 5-10 критичных алертов, использовать alert grouping
Нет трейсинга (только метрики и логи) Видно, что запрос медленный, но не видно где именно Добавить OpenTelemetry + Jaeger/Tempo
Prometheus single point of failure При падении Prometheus — нет метрик, нет алертов Использовать Prometheus HA (реплика 2, Alertmanager cluster)
Метрики собираются слишком часто (every 5s) Высокая нагрузка на Prometheus storage и network Ставить 15-30s для большинства метрик, 5s для критичных

Сравнительная таблица: Стек Observability

Компонент Метрики Логи Трейсы
Инструмент Prometheus Loki / ELK Jaeger / Tempo
Что показывает Цифры (CPU, latency, errors) События (log lines, stack traces) Путь запроса через сервисы
Метод сбора Pull (scrape) Push (agent → storage) Push (SDK → collector)
Хранение TSDB (15 дней) Index + chunks (30 дней) Trace index + span store
Query язык PromQL LogQL Trace ID lookup
Когда использовать Trends, alerting, dashboards Debug, audit, compliance Distributed tracing, bottleneck detection

Monitoring (Prometheus/Grafana) – метрики: CPU, RAM, latency, error rate. Logging (ELK/Loki) – логи: stdout/stderr контейнеров. Tracing (Jaeger/Zipkin) – распределённая трассировка: путь запроса через сервисы.

Когда НЕ использовать

  • Dev/локальная разработка —太重, используйте простые логи и health endpoints
  • Очень маленькие кластеры (1-2 Pod’а) — overhead Prometheus может превышать пользу
  • Когда нет команды для поддержки — мониторинг требует обслуживания: обновление дашбордов, настройка алертов, управление storage
  • Для бизнес-аналитики — Prometheus не замена data warehouse. Используйте ClickHouse/BigQuery для business analytics

🔴 Senior Level

Глубинная механика: Prometheus TSDB, Scraping, и Controller Reconciliation

Prometheus Architecture: Prometheus работает по pull model — сам опрашивает target’ы через HTTP /metrics эндпоинт.

  1. Service Discovery: Prometheus обнаруживает target’ы через Kubernetes API:
    • kubernetes_sd_configs с ролью pod, service, endpoints, node
    • Автоматически находит Pod’ы с аннотацией prometheus.io/scrape: "true"
    • Обновляет target list при изменении Pod’ов (через Kubernetes informer)
  2. Scraping: Каждые scrape_interval (15s по умолчанию):
    • HTTP GET /metrics endpoint
    • Parse text format (Prometheus exposition format)
    • Store in TSDB (Time-Series Database)
  3. TSDB (Time-Series Database):
    • Данные хранятся в виде blocks (2-hour chunks) на disk
    • Каждый block: index (series → chunks), chunks (raw samples), meta.json
    • WAL (Write-Ahead Log) для durability при crash
    • Compaction: 2h blocks → 4h → 8h → … (уменьшение cardinality)
    • Memory-mapped files для быстрого чтения
  4. Prometheus Operator (CoreOS):
    • Kubernetes Operator, управляющий Prometheus через CRD: Prometheus, ServiceMonitor, PodMonitor, PrometheusRule
    • ServiceMonitor — декларативное определение scrape targets (вместо ручного config)
    • Автоматически генерирует Prometheus config из CRD

kube-state-metrics Internals: kube-state-metrics подключается к API Server через informer’ы и генерирует метрики о состоянии K8s объектов:

kube_pod_status_phase{namespace="default", pod="my-app", phase="Running"} → 1
kube_deployment_status_replicas{namespace="default", deployment="my-app"} → 3
kube_persistentvolumeclaim_status_phase{namespace="default", pvc="data", phase="Bound"} → 1

Alertmanager: Prometheus отправляет firing alerts в Alertmanager. Alertmanager:

  1. Groups: Группирует похожие алерты (по label)
  2. Inhibition: Подавляет зависимые алерты (если node down, не алертить на каждый Pod на этой ноде)
  3. Routing: Отправляет в нужный receiver (Slack, PagerDuty, email)
  4. Deduplication: HA Prometheus (реплика 2) отправляет одинаковые alerts, Alertmanager дедуплицирует

OpenTelemetry (Tracing): OpenTelemetry SDK инструментрует приложение, собирает spans (отдельные операции) и группирует их в traces (полный путь запроса). Spans отправляются через OTLP protocol в collector → Jaeger/Tempo для хранения и визуализации.

Trade-offs

Аспект Trade-off
Pull vs Push Pull (Prometheus) = проще service discovery, но не работает для ephemeral targets. Push (StatsD) = работает для batch jobs, но нужен gateway
Prometheus vs VictoriaMetrics Prometheus = стандарт, огромное сообщество. VictoriaMetrics = лучше performance, меньше RAM, но менее зрелый ecosystem
Loki vs ELK Loki = легче, дешевле, лучше для K8s. ELK = мощнее full-text search, но тяжелее (Elasticsearch JVM)
Prometheus storage local vs remote Local = проще, но ограничен 15-30 днями. Remote (Thanos/Cortex) = долгосрочное хранение, но сложнее
High cardinality labels Больше labels = точнее queries, но exponentially больше series → больше RAM/CPU
Scrape interval Короткий (5s) = точнее, но выше нагрузка. Длинный (30s) = меньше нагрузка, но можно пропустить spikes

Prometheus хранит данные локально (обычно 15-30 дней). Для долгосрочного хранения используйте Thanos или Cortex.

Edge Cases (7+)

Edge Case 1: High Cardinality Explosion

# BAD: http_requests_total{path="/users/123", method="GET", status="200"}
# path содержит ID → уникальная series для каждого пользователя → millions of series

Cardinality explosion: Prometheus хранит каждую уникальную комбинацию labels как отдельную time series. 1000 users × 10 endpoints × 5 статусов = 50,000 series. Это съедает RAM и замедляет queries. Решение: использовать path="/users/:id" (группировка), а не конкретные ID.

Edge Case 2: Prometheus OOM при большом количестве series Prometheus хранит все active series в RAM. При 10 million series, Prometheus требует ~20-30GB RAM. Если лимит namespace ResourceQuota меньше, Prometheus OOMKilled. Решение: --storage.tsdb.max-block-duration=2h, cardinality limits, или VictoriaMetrics (меньше RAM footprint).

Edge Case 3: Scraping target исчезает до завершения scrape Pod удаляется во время scrape. Prometheus получает connection refused или partial response. Метрики за этот scrape lost. При частых деплоях (100+ Pod’ов/день), это создаёт gaps в метриках. Решение: honor_labels: true + scrape_timeout < scrape_interval.

Edge Case 4: Alertmanager notification flooding Node down → 50 Pod’ов на ноде не готовы → 50 алертов firing одновременно. Alertmanager отправляет 50 Slack сообщений. Команда получает alert fatigue. Решение: alert grouping (group_by: ['node']), inhibition rules (если node down, suppress pod alerts).

Edge Case 5: Tracing overhead OpenTelemetry с sampling: 1.0 (100% трейсов) добавляет 5-15% overhead к latency каждого запроса. При highload (10K RPS), это значительная деградация. Решение: probabilistic sampling (0.1-1%), или adaptive sampling (увеличивать sampling rate для errors).

Edge Case 6: Loki label cardinality Loki индексирует только labels, не content log lines. Если использовать pod_name как label, каждая уникальная комбинация labels = отдельный stream. При 1000 Pod’ов = 1000 streams. Решение: использовать label с меньшим cardinality (app, namespace), не pod_name.

Edge Case 7: Thanos/Cortex complexity Thanos добавляет sidecar (к Prometheus), query gateway, store gateway (S3), compactor, ruler. Это 5+ дополнительных компонентов. Для команды из 3 DevOps это может быть overhead. Решение: начать с Prometheus + 30-day retention, перейти на Thanos только при необходимости долгосрочного хранения.

Edge Case 8: kube-state-metrics API Server load kube-state-metrics watch’ит все K8s объекты через API Server informer’ы. При 5000 Pod’ов, 1000 Services, 500 Deployments, informer cache занимает ~500MB RAM. List/Watch операции добавляют нагрузку на API Server. Решение: --resources флаг для ограничения watch только нужными ресурсами.

Performance Numbers

Метрика Значение
Prometheus scrape latency 5-50ms на target (зависит от количества метрик)
Prometheus RAM per 1M series ~2-3GB
Prometheus disk per 1M series/day ~5-10GB (после compaction)
Max series per Prometheus instance ~10-20 million (зависит от RAM)
Query latency (simple) 10-100ms
Query latency (complex, 7d range) 1-10 секунд
Alertmanager notification latency 1-5 секунд (от firing до notification)
Loki ingestion latency 1-3 секунд (от log write до queryable)
OpenTelemetry overhead (0.1% sampling) <0.1% latency increase
OpenTelemetry overhead (100% sampling) 5-15% latency increase
kube-state-metrics RAM (5000 Pod’ов) ~500MB-1GB

Security

  • Prometheus endpoint не должен быть публичным/metrics раскрывает внутреннюю структуру приложения. Ограничить через NetworkPolicy
  • mTLS для scrape — если используется Istio, Prometheus scrape должен быть исключён из mTLS или использовать sidecar injection
  • RBAC для Prometheus SA — Prometheus Service Account требует get, list, watch на Pods, Services, Endpoints. Ограничить только нужными namespace’ами
  • Alertmanager webhook authentication — Slack/PagerDuty webhooks должны использовать authentication tokens, не plaintext URLs
  • Loki log sanitization — логи могут содержать sensitive data (PII, credentials). Использовать log redaction (Promtail pipeline stages) перед отправкой в Loki
  • Thanos/S3 encryption — долгосрочное хранение метрик в S3 должно быть encrypted (SSE-S3 или SSE-KMS)
  • OpenTelemetry collector authentication — OTLP endpoint должен требовать authentication (API key, mTLS), иначе любой может отправлять fake spans

Production War Story

Ситуация: SaaS-платформа, кластер 1000 Pod’ов, Prometheus + Grafana + Alertmanager. Приложение: Java/Spring Boot микросервисы с OpenTelemetry tracing.

Инцидент:

  1. Разработчик добавил метрику http_requests_total{path="/users/{id}", user_id="<actual-id>", ...} — user_id был фактическим ID пользователя, не шаблон
  2. За 2 часа cardinality выросла с 500K до 15 million series (100K unique user_id)
  3. Prometheus RAM usage вырос с 8GB до 25GB
  4. Prometheus OOMKilled (ResourceQuota limit: 20GB)
  5. Alertmanager перестал получать alerts — команда не узнала о проблеме
  6. Через 30 минут дежурный заметил, что Grafana дашборды пустые
  7. Prometheus restarted, но при startup replay WAL (Write-Ahead Log) → снова OOM → crash loop
  8. outage мониторинга на 4 часа, пока не удалили high-cardinality метрику и не увеличили RAM

Post-mortem и fix:

  1. Cardinality guard — Prometheus config --storage.tsdb.max-block-duration=2h + alert на series growth rate
  2. Metric naming conventionpath="/users/:id" (шаблон), не конкретные ID. Code review для новых метрик
  3. Prometheus HA — 2 реплики Prometheus с Alertmanager deduplication
  4. ResourceQuota для Prometheus namespace — отдельный namespace с гарантированными ресурсами
  5. Alert на Prometheus health — external health check (через synthetic monitoring), не зависимый от Prometheus
  6. Thanos для долгосрочного хранения — sidecar upload в S3, даже если Prometheus crashed

Мониторинг после fix:

# Alert: Prometheus series growth rate
rate(prometheus_tsdb_head_series[1h]) > 100000  # >100K new series/hour

# Alert: Prometheus memory usage
process_resident_memory_bytes{job="prometheus"} / 20e9 > 0.8  # >80% of 20GB

# Alert: Prometheus down (external check)
up{job="prometheus"} == 0

# Alert: Alertmanager not receiving alerts
rate(alertmanager_notifications_total{status="success"}[5m]) == 0

Monitoring (Prometheus/Grafana)

Ключевые метрики для мониторинга мониторинга:

# Prometheus health
up{job="prometheus"}

# Series count (cardinality)
prometheus_tsdb_head_series

# Scrape duration
rate(prometheus_target_interval_length_seconds_sum[5m])
/ rate(prometheus_target_interval_length_seconds_count[5m])

# TSDB compaction
rate(prometheus_tsdb_compactions_total[1h])

# Alertmanager alerts
alertmanager_alerts{state="firing"}

# kube-state-metrics latency
kube_state_metrics_list_duration_seconds

Ключевые метрики для приложения (Golden Signals):

# 1. Latency (p50, p95, p99)
histogram_quantile(0.50, rate(http_server_requests_seconds_bucket[5m]))
histogram_quantile(0.95, rate(http_server_requests_seconds_bucket[5m]))
histogram_quantile(0.99, rate(http_server_requests_seconds_bucket[5m]))

# 2. Traffic (RPS)
sum(rate(http_server_requests_seconds_count[5m])) by (service)

# 3. Errors (5xx rate)
sum(rate(http_server_requests_seconds_count{status=~"5.."}[5m]))
/ sum(rate(http_server_requests_seconds_count[5m]))

# 4. Saturation (CPU, memory, disk)
sum(rate(container_cpu_usage_seconds_total[5m])) by (pod)
container_memory_working_set_bytes / container_spec_memory_limit_bytes

Grafana Dashboard панели:

  1. Golden Signals Overview: Latency p50/p95/p99, Traffic RPS, Error Rate, Saturation (CPU/Memory)
  2. JVM Metrics: Heap/Non-Heap memory, GC pause time, thread count, class loading
  3. Kubernetes Overview: Pod status, Deployment replicas, PVC usage, Node resources
  4. Alerting Overview: Firing alerts by severity, alert rate, alertmanager notification latency
  5. Tracing Overview (Tempo/Jaeger): Trace count, error trace rate, slowest endpoints
  6. Prometheus Self-Monitoring: Series count, scrape duration, TSDB size, memory usage

Highload Best Practices

  1. Golden Signals: Latency, Traffic, Errors, Saturation — всегда мониторить эти 4 метрики
  2. Cardinality management — не использовать high-cardinality labels (user_id, request_id). Использовать шаблоны: path="/users/:id"
  3. Prometheus HA — 2 реплики Prometheus + Alertmanager с deduplication
  4. Scrape interval: 15s для большинства, 5s для критичных — баланс между accuracy и load
  5. Retention: 15 дней local + Thanos/Cortex для долгосрочного — S3 storage для compliance и trend analysis
  6. Alert routing by severity:
    • Critical → PagerDuty (немедленно)
    • Warning → Slack (в рабочее время)
    • Info → Email (ежедневный digest)
  7. Inhibition rules — если node down, не алертить на каждый Pod на этой ноде
  8. OpenTelemetry sampling: 0.1-1% для production, 100% для errors
  9. Loki label cardinality — использовать app, namespace, не pod_name
  10. Monitor the monitoring — external health check для Prometheus/Alertmanager, не зависимый от них
  11. Prometheus ResourceQuota — отдельный namespace с гарантированными 20-30GB RAM для 10M series
  12. Dashboard as code — Grafana dashboards в Git (JSON), деплой через CI/CD
  13. SLO/SLI tracking — определить Service Level Objectives (99.9% availability, p99 < 500ms) и track error budget
  14. Regular alert review — ежемесячный review firing alerts, удалять noisy alerts, добавлять missing

🎯 Шпаргалка для интервью

Обязательно знать:

  • Observability = Метрики (Prometheus) + Логи (Loki/ELK) + Трейсы (Jaeger/Tempo)
  • Prometheus — pull-модель, time-series DB; scrapes /metrics каждые 15-30 секунд
  • Golden Signals: Latency, Traffic, Errors, Saturation — всегда мониторить
  • kube-prometheus-stack = Prometheus + Grafana + Alertmanager + Node Exporter + kube-state-metrics
  • Cardinality explosion — главная проблема Prometheus (high-cardinality labels = OOM)
  • Для Java: JVM memory, GC pause, HTTP error rate, request latency (histogram_quantile)
  • Alert routing по severity: Critical → PagerDuty, Warning → Slack, Info → digest

Частые уточняющие вопросы:

  • «Почему cardinality explosion опасна?» — Каждая уникальная комбинация labels = series; millions series → OOM
  • «Prometheus HA — зачем?» — Single point of failure; 2 реплики + Alertmanager deduplication
  • «Pull vs Push?» — Pull (Prometheus) = проще service discovery; Push (StatsD) = для batch jobs
  • «Как мониторить мониторинг?» — External health check для Prometheus/Alertmanager, не зависимый от них

Красные флаги (НЕ говорить):

  • «Prometheus хранит метрики вечно» (локально 15-30 дней; Thanos/Cortex для долгосрочного)
  • «Мониторю только CPU/RAM» (нужны бизнес-метрики: error rate, latency, throughput)
  • «100% sampling для трейсинга в production» (5-15% overhead; используйте 0.1-1%)
  • «Alert fatigue — норма» (сократите до 5-10 критичных; иначе команда игнорирует)

Связанные темы:

  • [[Зачем нужны health checks]] — health endpoints для мониторинга
  • [[Как происходит масштабирование в Kubernetes]] — custom metrics для HPA
  • [[Что такое Kubernetes и зачем он нужен]] — мониторинг Control Plane