Observability в Kubernetes: объединяем логи, метрики и трейсы с Grafana Stack (Loki, Prometheus, Tempo) | AdminWiki

Observability в Kubernetes: объединяем логи, метрики и трейсы с Grafana Stack (Loki, Prometheus, Tempo)

26 июля 2026 13 мин. чтения

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-кластеры с предустановленным мониторингом и автоматическим масштабированием. Для команд, которые хотят сосредоточиться на разработке, а не на администрировании инфраструктуры, это сокращает время запуска с дней до часов.

Поделиться:
Сохранить гайд? В закладки браузера