Питання 24 · Розділ 14

Як моніторити додатки в Kubernetes?

Моніторинг — це приладова панель автомобіля. Спідометр показує швидкість (CPU usage), датчик температури — перегрів (memory usage), лампочка CHECK ENGINE — щось зламалося (error...

Мовні версії: 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, але експоненційно більше 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 втрачені. При частих деплоях (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