Як моніторити додатки в Kubernetes?
Моніторинг — це приладова панель автомобіля. Спідометр показує швидкість (CPU usage), датчик температури — перегрів (memory usage), лампочка CHECK ENGINE — щось зламалося (error...
🟢 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 будується на чотирьох компонентах:
- Prometheus — time-series database, збирає метрики методом pull (опитує ендпоинти кожні 15-30 секунд)
Prometheus – де-факто стандарт моніторингу в K8s. Pull-модель: Prometheus сам забирає метрики з Pod’ів через HTTP endpoint (/metrics).
- Node Exporter — DaemonSet на кожній ноді, збирає метрики ОС (CPU, RAM, disk, network)
- cAdvisor — вбудований в kubelet, збирає метрики контейнерів (CPU, memory, network per container)
- kube-state-metrics — Deployment, генерує метрики про K8s об’єкти (Pod status, Deployment replicas, PVC usage)
- 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 ендпоинт.
- Service Discovery: Prometheus виявляє target’и через Kubernetes API:
kubernetes_sd_configsз роллюpod,service,endpoints,node- Автоматично знаходить Pod’и з анотацією
prometheus.io/scrape: "true" - Оновлює target list при зміні Pod’ів (через Kubernetes informer)
- Scraping: Кожні
scrape_interval(15s за замовчуванням):- HTTP GET
/metricsendpoint - Parse text format (Prometheus exposition format)
- Store in TSDB (Time-Series Database)
- HTTP GET
- 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 для швидкого читання
- Prometheus Operator (CoreOS):
- Kubernetes Operator, що керує Prometheus через CRD:
Prometheus,ServiceMonitor,PodMonitor,PrometheusRule ServiceMonitor— декларативне визначення scrape targets (замість ручного config)- Автоматично генерує Prometheus config з CRD
- Kubernetes Operator, що керує Prometheus через 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:
- Groups: Групує схожі алерти (по label)
- Inhibition: Пригнічує залежні алерти (якщо node down, не алертити на кожен Pod на цій ноді)
- Routing: Надсилає в потрібний receiver (Slack, PagerDuty, email)
- 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.
Інцидент:
- Розробник додав метрику
http_requests_total{path="/users/{id}", user_id="<actual-id>", ...}— user_id був фактичним ID користувача, не шаблон - За 2 години cardinality зріс з 500K до 15 million series (100K unique user_id)
- Prometheus RAM usage зріс з 8GB до 25GB
- Prometheus OOMKilled (ResourceQuota limit: 20GB)
- Alertmanager перестав отримувати alerts — команда не дізналась про проблему
- Через 30 хвилин черговий помітив, що Grafana дашборди порожні
- Prometheus restarted, але при startup replay WAL (Write-Ahead Log) → знову OOM → crash loop
- outage моніторингу на 4 години, поки не видалили high-cardinality метрику і не збільшили RAM
Post-mortem та fix:
- Cardinality guard — Prometheus config
--storage.tsdb.max-block-duration=2h+ alert на series growth rate - Metric naming convention —
path="/users/:id"(шаблон), не конкретні ID. Code review для нових метрик - Prometheus HA — 2 репліки Prometheus з Alertmanager deduplication
- ResourceQuota для Prometheus namespace — окремий namespace з гарантованими ресурсами
- Alert на Prometheus health — external health check (через synthetic monitoring), не залежний від Prometheus
- 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 панелі:
- Golden Signals Overview: Latency p50/p95/p99, Traffic RPS, Error Rate, Saturation (CPU/Memory)
- JVM Metrics: Heap/Non-Heap memory, GC pause time, thread count, class loading
- Kubernetes Overview: Pod status, Deployment replicas, PVC usage, Node resources
- Alerting Overview: Firing alerts by severity, alert rate, alertmanager notification latency
- Tracing Overview (Tempo/Jaeger): Trace count, error trace rate, slowest endpoints
- Prometheus Self-Monitoring: Series count, scrape duration, TSDB size, memory usage
Highload Best Practices
- Golden Signals: Latency, Traffic, Errors, Saturation — завжди моніторити ці 4 метрики
- Cardinality management — не використовувати high-cardinality labels (user_id, request_id). Використовувати шаблони:
path="/users/:id" - Prometheus HA — 2 репліки Prometheus + Alertmanager з deduplication
- Scrape interval: 15s для більшості, 5s для критичних — баланс між accuracy та load
- Retention: 15 днів local + Thanos/Cortex для довгострокового — S3 storage для compliance та trend analysis
- Alert routing by severity:
- Critical → PagerDuty (негайно)
- Warning → Slack (в робочий час)
- Info → Email (щоденний digest)
- Inhibition rules — якщо node down, не алертити на кожен Pod на цій ноді
- OpenTelemetry sampling: 0.1-1% для production, 100% для errors
- Loki label cardinality — використовувати
app,namespace, неpod_name - Monitor the monitoring — external health check для Prometheus/Alertmanager, не залежний від них
- Prometheus ResourceQuota — окремий namespace з гарантованими 20-30GB RAM для 10M series
- Dashboard as code — Grafana dashboards в Git (JSON), деплой через CI/CD
- SLO/SLI tracking — визначити Service Level Objectives (99.9% availability, p99 < 500ms) та track error budget
- 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