Как мониторить приложения в Kubernetes?
Мониторинг — это приборная панель автомобиля. Спидометр показывает скорость (CPU usage), датчик температуры — перегрев (memory usage), лампочка CHECK ENGINE — что-то сломалось (...
🟢 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, но 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.
Инцидент:
- Разработчик добавил метрику
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