Tempo, Loki и Prometheus
Collector умеет принимать сигналы, но debug не хранит историю. Подключим три backend: Tempo для traces, Loki для logs и Prometheus для metrics. Grafana получит источники данных для каждого из них. В результате у «Пульса» появится конкретный путь от инструментирования до поиска, а не обещание «всё хранит OpenTelemetry». Эти компоненты выполняют разные операции и требуют отдельных правил доступа и retention.
Для лаборатории закреплены Tempo 2.7.2, Loki 3.4.2, Prometheus 3.2.1 и Grafana 11.6.0. Их выпуск подтверждён первичными источниками; выбран исторический согласованный набор для конкретного API. Контейнеры не запускались, поэтому совместимость конфигурации описана по документации, а не доказана выполненным стендом. Перед публичной эксплуатацией версии и безопасность обновляют и проверяют отдельно.
Traces в Tempo
Collector отправляет trace pipeline через otlphttp/tempo на внутренний адрес tempo:4318. Tempo принимает OTLP и хранит блоки в локальном volume лаборатории. Его HTTP query API доступен Grafana через порт 3200 внутри сети Compose. Порт приёма данных и порт поиска отличаются: источник Grafana обращается к query API, а приложение не должно отправлять spans на адрес интерфейса поиска.
Полный файл tempo.yaml состояния 08:
server:
http_listen_port: 3200
distributor:
receivers:
otlp:
protocols:
http:
endpoint: 0.0.0.0:4318
ingester:
max_block_duration: 5m
compactor:
compaction:
block_retention: 24h
storage:
trace:
backend: local
wal:
path: /var/tempo/wal
local:
path: /var/tempo/blocks
Retention traces задан сутками. Это подходит небольшой лаборатории, но не гарантирует сохранение producer для задания, которое выполняется позже. При длинных очередях срок traces согласуют с максимальным временем расследуемой операции. Volume сохраняет данные между обычными перезапусками контейнера, но локальный диск не становится распределённым резервным хранилищем автоматически. Отказ диска требует отдельного плана.
Поиск свежего trace может зависеть от состояния ingestion и блоков. Если данные ещё не доступны в выбранном пути поиска, отсутствие немедленного результата не доказывает потерю span. Поэтому полезно искать конкретный ID, проверять интервал и состояние exporter. В учебных материалах нет наблюдённых секунд появления trace или скриншота: реальная задержка стенда ещё не измерена.
Logs в Loki
Loki принимает OTLP logs через exporter с endpoint http://loki:3100/otlp. SDK отправляет данные Collector, а Collector добавляет необходимый путь сигнала. Не используем старый специальный Loki exporter как обязательный слой: выбран native OTLP приём. Для structured metadata нужен подходящий schema и allow_structured_metadata; в конфиге используется TSDB schema v13.
Полный файл loki.yaml состояния 08:
auth_enabled: false
server:
http_listen_port: 3100
common:
instance_addr: 127.0.0.1
path_prefix: /tmp/loki
storage:
filesystem:
chunks_directory: /tmp/loki/chunks
rules_directory: /tmp/loki/rules
replication_factor: 1
ring:
kvstore:
store: inmemory
schema_config:
configs:
- from: 2024-01-01
store: tsdb
object_store: filesystem
schema: v13
index:
prefix: index_
period: 24h
limits_config:
allow_structured_metadata: true
retention_period: 24h
compactor:
working_directory: /tmp/loki/compactor
retention_enabled: true
delete_request_store: filesystem
distributor:
otlp_config:
default_resource_attributes_as_index_labels: [service.name, deployment.environment.name]
Index labels ограничены service.name и окружением. Trace ID хранится как structured metadata, а не label потока. Такое разделение позволяет искать конкретный trace без создания отдельного indexed stream для каждой операции. При OTLP-нормализации точки в именах заменяются подчёркиваниями, поэтому LogQL использует service_name и trace_id. Синтаксис запроса зависит от реально сохранённого представления, а не от исходного названия поля в JavaScript.
В лаборатории auth_enabled:false означает отсутствие внутренней многопользовательской аутентификации Loki. Его порт не опубликован наружу, и Grafana обращается к нему внутри сети. Такое состояние нельзя переносить на публичный endpoint. Для реального сервиса доступ к backend ограничивают сетью, gateway и правами пользователей, а правила организации данных согласуют с возможностями multi-tenancy выбранной системы.
Metrics в Prometheus
В этом наборе Prometheus не принимает metrics тем же способом, что Tempo принимает traces. Collector exporter prometheus выставляет endpoint 8889, а Prometheus периодически scrapes его. Поэтому pipeline состоит из OTLP HTTP от Node до Collector и scrape от Prometheus до Collector. Если пропустить второй шаг, метрики могут находиться в памяти exporter, но не появляться в базе временных рядов.
Полный файл prometheus.yaml состояния 08:
global:
scrape_interval: 5s
evaluation_interval: 15s
rule_files: ["/etc/prometheus/alerts.yaml"]
scrape_configs:
- job_name: pulse-collector
static_configs:
- targets: [collector:8889]
Мы не копируем все resource attributes в metric labels. Приложение уже добавило bounded service label, который используется запросами. Exporter переводит имена и единицы в представление Prometheus: counter получает суффикс total, histogram секунд — соответствующие bucket/count/sum. Далее дашборд использует именно это ожидаемое представление. При будущей проверке нужно сверить реальные имена на endpoint, а не угадывать их по одной строке SDK.
Prometheus хранит данные в отдельном volume и ограничен сутками retention. Counter, histogram и gauge имеют разные правила запросов: для накопительного счётчика обычно нужен rate, для bucket — rate перед histogram_quantile, для текущего возраста очереди — gauge. Один общий график sum(value) не объясняет эти различия и способен дать неверные выводы о скорости или задержке.
Grafana как клиент источников
Grafana получает три datasources с фиксированными UID. Панели ссылаются на UID, а не на случайно введённое отображаемое имя. Это делает конфигурацию переносимой между лабораторными состояниями. Источники находятся в серверной сети Compose; адрес http://tempo:3200 доступен Grafana, хотя браузер пользователя не умеет разрешать имя tempo. Браузер обращается к Grafana, а её proxy выполняет запрос к backend.
Полный файл datasources.yaml состояния 08:
apiVersion: 1
datasources:
- name: Prometheus
uid: pulse-prom
type: prometheus
access: proxy
url: http://prometheus:9090
isDefault: true
- name: Tempo
uid: pulse-tempo
type: tempo
access: proxy
url: http://tempo:3200
- name: Loki
uid: pulse-loki
type: loki
access: proxy
url: http://loki:3100
Grafana публикуется только на loopback 3000 и требует заданный пароль администратора; anonymous access отключён. Пустые значения в .env.example требуют самостоятельного заполнения. Доступ к Grafana — доступ к операционным сведениям приложения, даже если мы исключили PII. Поэтому для команды поддержки вводят подходящие роли и право видеть только нужные источники, а не раздают административный пароль всем участникам.
Collector удаляет несколько известных опасных атрибутов перед экспортом. Это дополнительный рубеж, а не универсальная очистка лог body. Безопасная модель продолжает начинаться в приложении, где не собираются Authorization, query, payload и SQL-параметры. Сохранение данных в backend делает позднее удаление сложнее, поэтому надежда на скрытие колонок интерфейса не заменяет ограничение collection.
Ожидаемый результат восьмого состояния — Grafana имеет три источника, trace pipeline направлен в Tempo, logs в Loki, metrics доступны через Prometheus scrape. Числа, найденные записи и загрузка дисков не заявлены как полученные нами результаты. Следующая глава соединит эти источники в дашборд диагностики, сохраняя отдельную возможность проверить каждый участок пути при пустом или устаревшем графике.
Предыдущий урок: OpenTelemetry Collector и OTLP · Следующий урок: Дашборд для диагностики задержки
Оглавление серии · Исходники всех состояний.
Документация: Loki native OTLP, Prometheus exporter 0.123.0.