Как мониторить приложения в Kubernetes
Мониторинг — это приборная панель и бортовой самописец современного авиалайнера:
🟢 Junior Level
30-секундный ответ
Комплексный мониторинг (Observability / Наблюдаемость) в Kubernetes строится на концепции «Трёх китов наблюдаемости»:
- Метрики (Metrics — Что и когда происходит в цифрах?): числовые временные ряды (загрузка CPU/памяти, RPS, задержки p99, ошибки 5xx). Де-факто стандартом является связка Prometheus + Grafana.
- Логи (Logs — Почему это произошло?): текстовые потоки событий из
stdout/stderrконтейнеров. В Kubernetes их собирают DaemonSet-агенты (Promtail, Fluentbit, Vector) и отправляют в централизованные хранилища (Loki, Elasticsearch / OpenSearch). - Распределённая трассировка (Distributed Tracing — Где застрял запрос?): сквозной путь отдельного HTTP-запроса через десятки микросервисов с замером времени на каждом этапе (OpenTelemetry, Jaeger, Tempo).
Наглядная аналогия из жизни
Мониторинг — это приборная панель и бортовой самописец современного авиалайнера:
- Метрики: спидометр, высотомер, датчики оборотов двигателей и остатка топлива. Пилот видит общую картину полёта на экране (Grafana).
- Логи: журнал радиопереговоров и бортовой журнал ошибок (Black Box), куда поминутно записывается каждое действие экипажа.
- Трейсинг: навигационный трекер пути пассажирского багажа: регистрация $\to$ погрузка на рейс $\to$ пересадка в транзитном аэропорту $\to$ выдача (позволяет мгновенно понять, в каком именно аэропорту потерялась сумка).
Быстрый старт: Spring Boot 3 + Micrometer + Prometheus
В современных Java-микросервисах сбор метрик подключается добавлением двух зависимостей:
<!-- 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.yaml
management:
endpoints:
web:
exposure:
include: health,info,prometheus # Открыть эндпоинт /actuator/prometheus
metrics:
export:
prometheus:
enabled: true
🟡 Middle Level
Архитектура стека kube-prometheus-stack (Pull-модель)
[ Физические Ноды ] [ Kubelet / Cgroups ] [ API Server ] [ Java Spring Boot Pods ]
│ │ │ │
Node Exporter cAdvisor kube-state-metrics Micrometer
(Метрики ОС, RAM/CPU) (Метрики контейнеров) (Статусы подов, PVC) (/actuator/prometheus)
▲ ▲ ▲ ▲
└────────────────────────────┼─────────────────────────┼───────────────────────────┘
│ (Scrape каждые 15 секунд: HTTP GET)
[ Prometheus Server ] ──► Временные ряды (TSDB)
│
┌────────────────┴────────────────┐
▼ ▼
[ Grafana (Дашборды) ] [ Alertmanager (Slack/PagerDuty) ]
- Pull-модель Prometheus: Prometheus сам регулярно опрашивает (scrapes) цели по HTTP каждые 15–30 секунд через обнаружение сервисов (Service Discovery).
- Разделение источников метрик:
Node Exporter(DaemonSet): аппаратные метрики серверов (нагрузка на диск, сеть, ядра).cAdvisor(встроен в kubelet): потребление ресурсов контейнерами из Linux cgroups.kube-state-metrics(Deployment): логическое состояние объектов K8s (почему под упал в CrashLoop, сколько реплик живо, объем PVC).
Декларативный мониторинг через ServiceMonitor (Prometheus Operator)
Вместо ручного редактирования prometheus.yml используется Custom Resource Definition — ServiceMonitor:
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: payment-monitor
namespace: billing
labels:
release: prometheus # Лейбл оператора
spec:
selector:
matchLabels:
app: payment-service
endpoints:
- port: http-metrics
path: /actuator/prometheus
interval: 15s
Топ-5 PromQL запросов для Java-инженера
# 1. Загрузка Heap памяти JVM в процентах
(jvm_memory_used_bytes{area="heap"} / jvm_memory_max_bytes{area="heap"}) * 100
# 2. Суммарная длительность пауз сборщика мусора (GC Stop-The-World)
rate(jvm_gc_pause_seconds_sum[5m])
# 3. Количество HTTP-запросов в секунду (RPS)
sum(rate(http_server_requests_seconds_count[1m])) by (uri)
# 4. Процент ошибок HTTP 5xx от общего трафика
sum(rate(http_server_requests_seconds_count{status=~"5.."}[5m]))
/ sum(rate(http_server_requests_seconds_count[5m])) * 100
# 5. Время ответа API на 99-м перцентиле (Latency p99)
histogram_quantile(0.99, sum(rate(http_server_requests_seconds_bucket[5m])) by (le))
🔴 Senior Level
Катастрофа «Взрывной мощности меток» (Cardinality Explosion)
Самая частая причина падения серверов Prometheus в крупных компаниях — High Cardinality:
- Теория: Каждая уникальная комбинация пар
label=valueпорождает в базе данных Prometheus TSDB новую отдельную временную серию. - Катастрофическая ошибка разработчика:
// ❌ УБИЙСТВО ПРОМЕТЕУСА: запись уникального ID в лейбл метрики meterRegistry.counter("orders.created", "userId", order.getUserId(), // 10 000 000 уникальных ID "orderId", order.getOrderId() // 50 000 000 уникальных ID ).increment(); - Последствие: за несколько часов число серий подскакивает с 200 000 до 50 000 000. Prometheus TSDB съедает десятки гигабайт оперативной памяти, падает по
OOMKilled, а при перезапуске бесконечно висит на чтении WAL-лога (Write-Ahead Log). - Правило: лейблы должны содержать строго ограниченный набор значений (Low Cardinality): метод HTTP (
GET/POST), статус ответа (200/500), имя сервиса или тип ошибки (ValidationError/TimeoutException). Динамические идентификаторы клиентов (userId,orderId) должны писаться исключительно в логи или спаны трассировки (Tracing)!
Долгосрочное хранение и масштабирование: Thanos и VictoriaMetrics
Встроенная база данных Prometheus TSDB рассчитана на локальное хранение данных на SSD-диске в течение 15–30 дней. Она не умеет масштабироваться горизонтально. В Highload архитектурах применяются надстройки:
- Thanos: разворачивает
thanos-sidecarрядом с каждым Prometheus. Sidecar сжимает блоки метрик и непрерывно заливает их в дешевое объектное хранилище S3 (AWS S3, MinIO, Ceph).Thanos Querierпозволяет выполнять сквозные PromQL-запросы по истории метрик за 3–5 лет с автоматическим понижением дискретизации (Downsampling). - VictoriaMetrics: легковесная альтернатива Prometheus TSDB с многократной экономией оперативной памяти (в 4–7 раз) и нативной поддержкой протокола PromQL и долгосрочного хранения.
Накладные расходы OpenTelemetry Tracing в High-Load
В распределенных микросервисах прохождение каждого запроса генерирует цепочку спанов с уникальным traceparent (стандарт W3C TraceContext):
- Проблема Overhead: при потоке в 50 000 RPS сохранение 100% трейсов создаёт гигантскую нагрузку на CPU сериализации, переполняет буферы оперативной памяти JVM и забивает сеть кластера терабайтами телеметрии.
- Архитектурное решение — Tail-Based Sampling (Сэмплирование на выходе):
- Микросервисы отправляют трейсы на выделенный кластер OpenTelemetry Collector.
- Collector временно держит весь жизненный цикл запроса в оперативной памяти.
- Если запрос завершился с кодом HTTP 200 за 15 мс, он отбрасывается (drop).
- Если запрос завершился с ошибкой HTTP 500 или задержка превысила 1 секунду, этот трейс сохраняется со всеми деталями (100% сохранение аномалий)!
4 Tricky Questions
1. Почему Prometheus использует Pull-модель сбора метрик по умолчанию, и как с его помощью мониторить короткоживущие задачи (CronJobs, Serverless Functions), завершающиеся быстрее интервала сбора?
Ответ:
- Преимущества Pull: сервер Prometheus сам контролирует темп сбора данных (Rate Control), что предотвращает отказ мониторинга от наплыва входящих сообщений (DDoS от собственных приложений). Кроме того, если сервис перестал отвечать на scrape-запрос, Prometheus моментально фиксирует статус
up == 0(Health Check из коробки). - Решение для короткоживущих CronJobs: если контейнер запускается, считает задачу за 3 секунды и умирает, стандартный опрос (раз в 15 с) никогда его не поймает.
- Для этого в стек внедряется промежуточный шлюз
Prometheus Pushgateway:- Короткоживущий джоб при завершении сам отправляет (Push) свои финальные метрики в Pushgateway через HTTP POST.
- Pushgateway сохраняет метрики в памяти.
- Prometheus спокойно опрашивает Pushgateway по стандартной Pull-модели в своем регулярном ритме.
2. В чём состоит принципиальная разница между cAdvisor и kube-state-metrics? Какая из систем покажет, почему Под ушёл в CrashLoopBackOff?
Ответ:
cAdvisor(Container Advisor): собирает физические телеметрические метрики использования ресурсов ядра ОС из подсистемы Linux cgroups (фактические наносекунды CPU, байты resident памяти, ввод-вывод диска, переданные сетевые пакеты). Он ничего не знает о концепциях Kubernetes (деплойменты, манифесты).kube-state-metrics: слушает событияkube-apiserverчерез informer’ы и преобразует декларативное состояние объектов Kubernetes в формат метрик.- Именно
kube-state-metricsсгенерирует метрикуkube_pod_container_status_waiting_reason{reason="CrashLoopBackOff"}и покажет код возвратаexitCode: 137или1, а также количество рестартов и готовность реплик в Deployment.cAdvisorпричину падения пода показать не способен.
3. Как сборщик мусора HotSpot JVM (GC Stop-The-World) может исказить метрики задержки (Latency), собираемые внутри Java-приложения, и как это обнаружить?
Ответ: Если метрика времени выполнения запроса замеряется внутри кода Java через таймер Micrometer:
- Во время паузы Full GC (STW) все потоки приложения замораживаются, включая системный таймер приложения.
- Если клиент отправил запрос, а JVM в этот момент ушла в GC-паузу на 2 секунды, клиент увидит задержку 2010 мс. Однако внутренний замер времени в контроллере Java может начаться только ПОСЛЕ окончания сборки мусора и показать «чистое» время обработки 10 мс!
- Как обнаружить расхождение: сопоставить внутренние метрики latency приложения с внешними замерами на уровне Ingress Controller (Nginx
$request_time) или Service Mesh (Envoy). Разница между Ingress Latency и App Latency точно соответствует длительности паузы STW GC и очереди в сокетах Linux.
4. Каким образом реализуется сквозная передача контекста трассировки (Trace Context Propagation) в асинхронных приложениях на Java (CompletableFuture, Reactive WebFlux, Virtual Threads)?
Ответ:
Классические библиотеки трассировки (Sleuth, ранний OpenTelemetry) сохраняли TraceId и SpanId в локальной памяти потока — ThreadLocal:
- При переключении контекста в асинхронных пулах (
CompletableFuture.supplyAsync, Project Reactor / WebFlux) поток исполнения меняется, и данныеThreadLocalтеряются, из-за чего единый трейс разрывается на несвязанные куски. - Решения:
- В реактивном стеке (Spring WebFlux): контекст трассировки оборачивается в иммутабельный реактивный контекст
reactor.util.context.Context, распространяемый вверх по стриму операторов. - В OpenTelemetry SDK: использование инструментации байт-кода Java Agent (
-javaagent:opentelemetry-javaagent.jar), который перехватывает фабрики потоковExecutorи автоматически копируетContextмежду рабочими потоками. - В Java 21+ с Virtual Threads: легковесные виртуальные потоки корректно наследуют значения через механизм
Scoped Values(JEP 446 / JEP 481) или оптимизированныеInheritableThreadLocal.
- В реактивном стеке (Spring WebFlux): контекст трассировки оборачивается в иммутабельный реактивный контекст
🎯 Шпаргалка для интервью
Главное о мониторинге Kubernetes
- Три столпа Observability: Метрики (Prometheus), Логи (Loki / ELK), Трейсы (OpenTelemetry / Jaeger).
- Стандарт метрик: Prometheus (Pull-модель, TSDB, сбор раз в 15–30 с через
/actuator/prometheus). - Связка агентов:
Node Exporter$\to$ железо нод.cAdvisor$\to$ CPU/RAM контейнеров из cgroups.kube-state-metrics$\to$ статусы подов, рестарты, фазы K8s объектов.
- Главный враг TSDB — Cardinality Explosion: категорически запрещено передавать в метрики Prometheus динамические ID (пользователи, заказы, UUID).
- Масштабирование: локально 15–30 дней $\to$ для долгосрочного хранения в S3 используются Thanos или VictoriaMetrics.
- Golden Signals: Latency (p95/p99), Traffic (RPS), Errors (5xx), Saturation (CPU/RAM).
Инструменты мониторинга по категориям
| Направление | Инструменты | Протокол / Язык | Назначение | | :— | :— | :— | :— | | Метрики | Prometheus, VictoriaMetrics | PromQL / Pull | Графики трендов, алертинг в реальном времени | | Логи | Grafana Loki, Fluentbit, Vector | LogQL / Push | Поиск stack trace, аудит событий и ошибок | | Трейсинг | OpenTelemetry, Jaeger, Tempo | OTLP / W3C Trace | Поиск узких мест в цепочках микросервисов |
Красные флаги на собеседовании (Чего говорить нельзя)
- ❌ «Мы добавляем user_id в лейблы метрик Prometheus, чтобы видеть запросы каждого клиента» — гарантированный Cardinality Explosion и падение мониторинга.
- ❌ «Prometheus собирает логи приложений из stdout контейнеров» — Prometheus работает исключительно с числовыми временными рядами; для логов нужен Loki или ELK.
- ❌ «Мы храним метрики в стандартной базе Prometheus за последние 3 года» — стандартный TSDB не предназначен для этого; требуется Thanos или VictoriaMetrics.