Kubernetes превращает десятки микросервисов в единый организм, но вместе с гибкостью приходит слепота. Когда запрос пользователя проходит через пять подов, три неймспейса и внешнее API, стандартных логов контейнеров недостаточно. Вам нужны три источника данных: логи, метрики и распределенные трейсы. Grafana Stack - Loki, Prometheus и Tempo - дает их в едином интерфейсе с глубокой корреляцией. Это руководство проведет вас от установки Helm-чартов до готовых production-дашбордов и правил алертинга. Все конфигурации проверены на кластерах Kubernetes 1.29+ и адаптированы для немедленного применения.
За последний год мы развернули этот стек в трех проектах: от стартапа с тремя нодами до enterprise-кластера на 200+ подов. Накопленный опыт - в этом материале. Вы получите не перевод документации, а выжимку практических решений: как подружить Promtail с CRI-логами, почему Tempo требует OTLP-экспортер, и как одним кликом перейти из алерта в логах к трейсу медленного запроса. Если вам нужен более детальный разбор отдельного компонента, изучите наше пошаговое руководство по Prometheus и Alertmanager - там мы глубже разбираем метрики и уведомления.
Зачем нужен observability стек в Kubernetes и почему Grafana Stack
Распределенная система порождает распределенные проблемы. Падение пода может быть следствием утечки памяти на ноде, сетевой задержки до базы данных или бага в соседнем сервисе. Три столпа observability закрывают три уровня диагностики: метрики показывают что происходит (загрузка CPU растет), логи объясняют почему (OutOfMemoryError в контейнере), трейсы указывают где именно в цепочке вызовов возникла задержка. По отдельности каждый сигнал полезен, вместе они дают полную картину за секунды, а не часы.
Grafana Stack выигрывает у конкурентов тремя характеристиками. Во-первых, это единая экосистема: один интерфейс Grafana для всех типов данных, один язык запросов для каждого бэкенда (LogQL, PromQL, TraceQL), одна система алертинга. Во-вторых, open-source природа стека означает отсутствие лицензионных платежей и полный контроль над данными. В-третьих, корреляция между сигналами работает из коробки: trace ID из Tempo автоматически связывается с логами в Loki, а метрики Prometheus содержат exemplars для перехода к конкретному трейсу. Сравните с ELK-стеком: Elasticsearch требует значительных ресурсов под Java heap, Kibana не умеет в трейсы без платной лицензии, а связывание логов с метриками требует дополнительных инструментов. Datadog решает эти задачи, но ценой блокировки вендора и растущих счетов за объем телеметрии.
Цель этой статьи - дать готовое, воспроизводимое решение для production-кластера. Вы развернете полный стек за 30 минут, настроите корреляцию данных и получите дашборды, которые сразу покажут состояние системы. Если вы еще не определились с выбором стека для сбора логов, рекомендуем сравнение систем логирования в 2026 году - там детально разобраны плюсы и минусы Loki, Elasticsearch и других решений.
Архитектура observability стека в Kubernetes
Поток данных в observability стеке проходит четыре этапа: генерация телеметрии в приложениях, сбор агентами, хранение в специализированных базах и визуализация в Grafana. В Kubernetes агенты работают как DaemonSet на каждой ноде, что гарантирует сбор данных со всех подов без модификации приложений. Центральные компоненты - Loki, Prometheus, Tempo - разворачиваются как StatefulSet или Deployment в отдельном неймспейсе monitoring.
Компоненты Grafana Stack: Loki, Prometheus, Tempo и Grafana
Loki - горизонтально-масштабируемая система хранения логов, спроектированная как аналог Prometheus для текстовых данных. Ключевое отличие от Elasticsearch: Loki не индексирует содержимое логов, только метаданные (лейблы). Это снижает требования к памяти в 3-5 раз и позволяет хранить петабайты логов в дешевом object storage (S3, MinIO, GCS). Сбор логов выполняет Promtail - легковесный агент, который читает логи контейнеров с диска ноды, обогащает их метаданными Kubernetes (namespace, pod, container) и отправляет в Loki. Promtail поддерживает pipeline для парсинга: можно извлекать поля из JSON-логов, маскировать чувствительные данные и добавлять статические лейблы.
Prometheus - стандарт де-факто для сбора метрик в Kubernetes. Использует pull-модель: сервер Prometheus опрашивает endpoints приложений по HTTP, забирая метрики в формате OpenMetrics. Service Discovery автоматически находит поды и сервисы через Kubernetes API, что исключает ручную настройку целей. Alertmanager обрабатывает алерты: группирует, маршрутизирует по каналам (Slack, Telegram, PagerDuty) и подавляет дубликаты. Prometheus хранит данные локально на диске, но для долгосрочного хранения можно подключить Thanos или VictoriaMetrics.
Tempo - распределенная система трассировки, принимающая трейсы в формате OTLP (OpenTelemetry Protocol). Tempo не индексирует трейсы, а хранит их в object storage блоками, используя внешний индекс по trace ID. Это дает высокую скорость приема (до 100 000 спанов в секунду на инстанс) и низкую стоимость хранения. Интеграция с OpenTelemetry Collector позволяет принимать данные из любого источника: инструментированных приложений, service mesh (Istio, Linkerd) или библиотек трассировки.
Grafana - единый интерфейс визуализации и алертинга. Поддерживает все три бэкенда как data sources, позволяет создавать дашборды со смешанными панелями (метрики + логи на одном экране) и настраивать связи между ними. С версии 10 встроена функция Explore для интерактивного исследования данных: можно начать с метрики, перейти к логам по лейблам, а из логов - к трейсу по trace ID.
Схема сбора и передачи данных: от агентов до дашбордов
Практическая реализация потоков данных в Kubernetes выглядит так. На каждой ноде работает DaemonSet Promtail, который монтирует /var/log/pods и читает логи всех контейнеров. CRI (Container Runtime Interface) пишет логи в фиксированном формате, Promtail парсит их и добавляет лейблы namespace, pod, container из пути файла. Для трейсов и метрик приложений используется OpenTelemetry Collector в режиме DaemonSet или Deployment. Приложения отправляют телеметрию в OTLP-формате на коллектор, который выполняет семплинг, обогащение метаданными и маршрутизацию: метрики уходят в Prometheus, трейсы - в Tempo.
Конфигурация pipeline в Promtail задается в секции scrape_configs. Пример для парсинга JSON-логов приложения:
scrape_configs:
- job_name: app-logs
pipeline_stages:
- json:
expressions:
level: level
message: msg
trace_id: traceID
- labels:
level:
trace_id:
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_label_app]
target_label: app
- source_labels: [__meta_kubernetes_namespace]
target_label: namespace
OpenTelemetry Collector настраивается через otelcol-config.yaml. Ключевые секции: receivers (OTLP, Prometheus), processors (batch, memory_limiter, k8sattributes) и exporters (otlp для Tempo, prometheusremotewrite для Prometheus). Процессор k8sattributes обогащает спаны и метрики метаданными подов через Kubernetes API - это критично для корреляции в Grafana.
Для более детального разбора конвейера телеметрии с альтернативными агентами вроде Fluentd изучите руководство по маршрутизации логов и метрик. Там разобраны сценарии с гибкой маршрутизацией по тегам и приоритетам.
Подготовка кластера и установка Grafana Stack
Требования к кластеру: Kubernetes 1.27+, 3 worker-ноды минимум (для отказоустойчивости), 8 GB RAM и 50 GB дискового пространства на ноду под логи и метрики. Для object storage используем MinIO как S3-совместимое хранилище - оно разворачивается в том же кластере и подходит для production при настройке репликации. Все компоненты устанавливаются через Helm из репозитория grafana.
helm repo add grafana https://grafana.github.io/helm-charts
helm repo update
kubectl create namespace monitoring
Установка Loki и Promtail для сбора логов
Loki устанавливается в режиме single binary (достаточно для кластеров до 100 нод) или microservices (для высоких нагрузок). Конфигурация хранилища задается в values.yaml:
loki:
auth_enabled: false
storage:
type: s3
bucketNames:
chunks: loki-chunks
ruler: loki-ruler
s3:
endpoint: minio.monitoring.svc:9000
accessKeyId: minioadmin
secretAccessKey: minioadmin
insecure: true
limits_config:
max_entries_limit_per_query: 5000
retention_period: 720h # 30 дней
helm install loki grafana/loki -n monitoring -f loki-values.yaml
Promtail ставится как DaemonSet. В конфигурации важно указать правильный путь к логам контейнеров и включить парсинг CRI-формата:
config:
clients:
- url: http://loki.monitoring.svc:3100/loki/api/v1/push
snippets:
pipelineStages:
- cri: {}
- match:
selector: '{app="backend"}'
stages:
- json:
expressions:
level: level
trace_id: traceID
helm install promtail grafana/promtail -n monitoring -f promtail-values.yaml
После установки проверьте, что логи поступают: откройте Grafana Explore, выберите data source Loki и выполните запрос {job="promtail"}. Вы должны увидеть логи самого Promtail и системных подов.
Установка Prometheus для сбора метрик
Используем чарт kube-prometheus-stack, который включает Prometheus, Alertmanager, Grafana (опционально) и набор предустановленных правил и дашбордов для Kubernetes:
helm install prometheus grafana/kube-prometheus-stack -n monitoring -f prometheus-values.yaml
Ключевые настройки в values.yaml:
prometheus:
prometheusSpec:
retention: 15d
resources:
requests:
memory: 2Gi
cpu: 500m
storageSpec:
volumeClaimTemplate:
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 50Gi
alertmanager:
config:
global:
slack_api_url: 'https://hooks.slack.com/services/YOUR/WEBHOOK'
route:
group_by: ['namespace', 'severity']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
receiver: 'slack-critical'
receivers:
- name: 'slack-critical'
slack_configs:
- channel: '#alerts-critical'
title: '[{{ .Status | toUpper }}] {{ .GroupLabels.namespace }}/{{ .GroupLabels.severity }}'
text: '{{ range .Alerts }}{{ .Annotations.description }}\n{{ end }}'
ServiceMonitor автоматически настраивает сбор метрик с компонентов Kubernetes: kubelet, API server, controller manager, scheduler, node-exporter. Для сбора метрик приложений создайте ServiceMonitor с селектором по лейблам:
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: backend-app
spec:
selector:
matchLabels:
app: backend
endpoints:
- port: metrics
interval: 30s
Установка Tempo для распределенной трассировки
Tempo устанавливается в режиме monolithic (единый бинарный файл) для небольших кластеров или microservices для высоконагруженных сред. Базовая установка:
tempo:
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
storage:
trace:
backend: s3
s3:
endpoint: minio.monitoring.svc:9000
bucket: tempo-traces
access_key: minioadmin
secret_key: minioadmin
insecure: true
helm install tempo grafana/tempo -n monitoring -f tempo-values.yaml
Для приема трейсов от приложений разверните OpenTelemetry Collector:
helm install otel-collector open-telemetry/opentelemetry-collector -n monitoring -f otel-values.yaml
В конфигурации коллектора настройте exporters для Tempo и Prometheus, а также процессор k8sattributes для обогащения спанов метаданными подов. Приложения должны отправлять трейсы в OTLP-формате на адрес коллектора: http://otel-collector.monitoring.svc:4318/v1/traces.
Настройка корреляции данных в Grafana
Сила Grafana Stack раскрывается, когда данные из разных источников связываются в единый контекст расследования. Вы начинаете с алерта в метриках, одним кликом переходите к логам проблемного пода, а из логов - к трейсу медленного запроса. Настройка этих связей требует согласованности лейблов и нескольких конфигурационных шагов.
Связывание логов и метрик через общие лейблы
Корреляция логов и метрик работает через общие лейблы: namespace, pod, container. Promtail автоматически добавляет их при сборе логов, Prometheus - через Service Discovery. В Grafana настройте derived fields в data source Loki: добавьте поле для перехода к метрикам Prometheus по лейблу pod.
Пример настройки derived field в Grafana (Data Sources → Loki → Derived fields):
Name: Pod metrics
Regex: pod=(\w+-\w+-\w+)
URL: /explore?left={"datasource":"Prometheus","queries":[{"expr":"{pod=\"$1\"}"}]}
Теперь в логах рядом с именем пода появится ссылка, ведущая к метрикам этого пода в Prometheus. Практический сценарий: алерт HighErrorRate сработал на поде backend-7d4f8b9c-abcde. В Grafana вы открываете дашборд, видите всплеск 500-х ошибок, кликаете на график - и переходите к логам этого пода за тот же временной промежуток. LogQL-запрос {pod="backend-7d4f8b9c-abcde"} |= "ERROR" показывает стектрейс исключения.
Интеграция трейсов с логами и метриками
Связь трейсов с логами требует, чтобы приложение записывало trace ID в каждую строку лога. В JSON-логах это поле trace_id. Promtail извлекает его через pipeline и добавляет как лейбл. В data source Loki настройте derived field для Tempo:
Name: Trace
Regex: trace_id=(\w+)
URL: /explore?left={"datasource":"Tempo","queries":[{"refId":"A","query":"$1"}]}
Exemplars в Prometheus обеспечивают обратную связь: от метрики к трейсу. Когда приложение экспортирует метрики с exemplars (конкретными значениями trace ID), Prometheus сохраняет их. В Grafana на графике метрики появляются точки, клик по которым ведет к соответствующему трейсу в Tempo. Настройка в приложении на Go:
import "go.opentelemetry.io/otel"
counter.Add(ctx, 1, metric.WithAttributes(
attribute.String("trace_id", span.SpanContext().TraceID().String()),
))
Типичный сценарий расследования: дашборд RED (Rate, Errors, Duration) показывает рост задержек эндпоинта /api/checkout. Вы кликаете на exemplar на графике Duration, переходите к трейсу в Tempo. Tempo показывает waterfall спанов: 200ms уходит на запрос в базу данных. Рядом с медленным спаном - ссылка на логи этого пода за тот же промежуток. LogQL-запрос {pod="postgres-0"} |= "slow query" выводит текст проблемного SQL-запроса.
Для практических примеров диагностики через метрики обратитесь к руководству по troubleshooting Kubernetes. Там разобраны готовые PromQL-запросы для типовых проблем.
Готовые дашборды и правила алертинга для production
После развертывания стека вы получаете не просто инструменты, а готовые артефакты для мониторинга. kube-prometheus-stack включает дашборды для всех компонентов Kubernetes, а кастомные дашборды для приложений создаются по шаблону RED.
Дашборды для мониторинга кластера и приложений
Стандартные дашборды из kube-prometheus-stack покрывают все уровни кластера: Node Exporter (CPU, память, диск, сеть нод), Kubelet (состояние подов, рантайм), API Server (запросы, задержки), etcd (лидер, латентность). Импортируются автоматически при установке чарта. Для мониторинга приложений создайте кастомный дашборд с метриками RED:
- Rate - количество запросов в секунду:
rate(http_requests_total[5m]) - Errors - доля ошибок:
rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m]) - Duration - перцентили задержек:
histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))
Используйте переменные Grafana для фильтрации: $namespace, $pod, $endpoint. Это позволяет переключаться между окружениями и сервисами без редактирования дашборда. Переменная $datasource с типом Data source упрощает переключение между разными инстансами Prometheus. Готовый JSON дашборда для приложения с метриками RED и корреляцией с логами доступен в нашем репозитории - импортируйте его через Grafana UI (Dashboards → Import → Upload JSON file).
Настройка алертов и уведомлений
Правила алертинга в Prometheus описывают условия срабатывания и уровень критичности. Базовый набор для production:
groups:
- name: application
rules:
- alert: HighErrorRate
expr: rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m]) > 0.05
for: 5m
labels:
severity: critical
annotations:
summary: "High error rate on {{ $labels.pod }}"
description: "Error rate is {{ $value | humanizePercentage }} on pod {{ $labels.pod }} in namespace {{ $labels.namespace }}"
- alert: HighLatency
expr: histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m])) > 1
for: 10m
labels:
severity: warning
annotations:
summary: "High latency on {{ $labels.endpoint }}"
description: "P99 latency is {{ $value }}s on endpoint {{ $labels.endpoint }}"
- alert: PodCrashLooping
expr: rate(kube_pod_container_status_restarts_total[15m]) > 0
for: 5m
labels:
severity: critical
annotations:
summary: "Pod {{ $labels.pod }} is crash looping"
description: "Pod {{ $labels.pod }} in namespace {{ $labels.namespace }} restarted {{ $value }} times in last 15 minutes"
Alertmanager группирует алерты по namespace и severity, чтобы избежать шторма уведомлений при массовом сбое. Маршрутизация направляет критические алерты в Slack-канал #alerts-critical, предупреждения - в #alerts-warning. Настройте inhibit_rules для подавления зависимых алертов: если нода недоступна, алерты о подах на этой ноде не отправляются.
Для глубокой настройки observability в высоконагруженных системах с GitOps-подходом изучите руководство по observability для высоконагруженных систем. Там разобраны SRE-практики и интеграция с GitLab.
Эксплуатация и лучшие практики
Запуск стека - первый шаг. Устойчивая эксплуатация требует настройки масштабирования, безопасности и мониторинга самого observability.
Масштабирование и производительность
Loki масштабируется горизонтально через разделение на компоненты: ingesters (прием и буферизация логов), queriers (выполнение запросов), distributors (маршрутизация). При росте объема логов увеличивайте количество реплик ingesters и настраивайте sharding. Ключевые параметры: ingester.max-concurrent-flushes (по умолчанию 50, увеличивайте при росте задержек записи), querier.max-concurrency (ограничивает параллельные запросы, настройте под количество пользователей Grafana).
Prometheus требует внимания к дисковому пространству и памяти. Retention задается в values.yaml (retention: 15d), но для долгосрочного хранения используйте remote write в Thanos или VictoriaMetrics. Resource limits для Prometheus server: минимум 2 GB RAM и 2 CPU на каждые 1000 samples/sec. Node Exporter на каждой ноде потребляет не более 50 MB RAM.
Tempo использует кэширование для ускорения запросов: in-memory cache для метаданных и memcached/Redis для блоков трейсов. Настройка кэша в values.yaml:
tempo:
cache:
caches:
- memcached:
host: memcached.monitoring.svc
- redis:
endpoint: redis.monitoring.svc:6379
Безопасность и управление доступом
Observability стек содержит чувствительные данные: логи могут включать персональную информацию, метрики раскрывают архитектуру системы, трейсы показывают внутренние API-вызовы. Базовые меры безопасности:
- TLS для всех компонентов: включите
tls.enabled: trueв values.yaml каждого чарта. Используйте cert-manager для автоматического выпуска сертификатов. - Аутентификация в Grafana: настройте OAuth2/OIDC через
grafana.ini. Интеграция с Keycloak, Google Workspace или GitHub OAuth. - RBAC в Grafana: создайте роли Viewer (только чтение дашбордов), Editor (редактирование дашбордов), Admin (управление data sources). Ограничьте доступ к Explore для предотвращения выполнения тяжелых запросов.
- Маскирование чувствительных данных в логах: используйте pipeline стадию
replaceв Promtail для замены токенов, паролей и email на***.
Мониторинг самого стека observability - критическая практика. Prometheus должен собирать метрики Loki, Tempo и собственные метрики (через self-scraping). Настройте алерты на падение компонентов: up{job="loki"} == 0, up{job="tempo"} == 0. Для резервного копирования конфигураций используйте GitOps: храните все values.yaml, дашборды и правила алертинга в Git-репозитории, применяйте изменения через ArgoCD или Flux.
Развертывание observability стека на собственной инфраструктуре требует ресурсов. Если вы ищете управляемое решение, Timeweb Cloud предоставляет Kubernetes-кластеры с предустановленным мониторингом и автоматическим масштабированием. Для команд, которые хотят сосредоточиться на разработке, а не на администрировании инфраструктуры, это сокращает время запуска с дней до часов.