Як моніторити додатки в 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.