OSEN-НИЙ SAAALEСкидка 50% на виртуальный хостинг и VDS
до 30.11.2025 Подробнее
Выберите продукт

NGINX OpenTelemetry: otel‑модуль и OTLP‑exporter для трассировок и метрик

Разбираем, как подружить NGINX с OpenTelemetry на проде: варианты установки otel‑модуля, настройка OTLP exporter (gRPC и HTTP), интеграция с Collector, прокидывание trace‑контекста, сбор метрик и контроль кардинальности. Плюс чек‑лист внедрения, диагностика и рекомендации по оверхеду.
NGINX OpenTelemetry: otel‑модуль и OTLP‑exporter для трассировок и метрик

OpenTelemetry прочно закрепился как де‑факто стандарт наблюдаемости: единая модель для трассировок (tracing), метрик (metrics) и логов (logs), универсальные SDK и единственный протокол доставки — OTLP (вкус gRPC и HTTP/protobuf). Когда на периметре у вас стоит NGINX, логично собирать с него и «входные» трассы запросов, и полезные метрики фронта — без самописных обвязок. Для этого существует otel‑модуль NGINX (OpenTelemetry module for NGINX): он автоматически создаёт спаны на каждый HTTP‑запрос и экспортирует их, а также метрики, по OTLP в Collector.

Что даёт OpenTelemetry на уровне NGINX

Без агентских хакингов и парсинга логов мы получаем:

  • Трассировки входящих HTTP‑запросов: корневой span на стороне NGINX с атрибутами по спецификации (например, http.method, http.route, http.target, http.status_code, user_agent.original, network.peer.address, server.address и др.).
  • Корректную W3C Trace Context‑пропагацию (traceparent, tracestate) к бэкендам, чтобы цепочки спанов не рвались.
  • Метрики уровня NGINX: счётчики/гистограммы по длительностям, размеру тел, количеству запросов, статусам и т. д. (поддержка зависит от версии модуля; как минимум базовые HTTP‑метрики доступны).
  • Единый канал доставки — OTLP (gRPC на 4317 или HTTP/protobuf на 4318). Дальше Collector преобразует данные в нужные системы хранения и визуализации.

Сильная сторона подхода — «чистая» модель: модуль работает внутри процесса NGINX, видит все фазы запроса, создаёт спаны с правильным контекстом и отдаёт их локальному Collector. Никаких парсеров access‑логов и разночтений семантики.

Архитектура: где здесь exporter

Схема предсказуемая: otel‑модуль внутри NGINX выступает источником сигналов и использует OpenTelemetry SDK, а «экспортёр» — это фактически OTLP‑клиент, зашитый в модуль. Он отправляет трассы и метрики в локальный Collector по OTLP. Зачем локальный Collector?

  • Буферизация и ретраи при сетевых сбоях.
  • Понижение кардинальности и нормализация атрибутов.
  • Фан‑аут: один приёмник — несколько мест назначения (APM для трасс, Prometheus для метрик).
  • Единая TLS/аутентификация наружу, при том что NGINX общается по localhost.

Настройка переменных OTEL для NGINX через systemd drop‑in

Установка otel‑модуля: варианты

Есть два распространённых пути:

  1. Готовый динамический модуль от вашего дистрибутива или вендорского репозитория NGINX. Плюс — быстрее всего, минус — нужно совпадение версий NGINX и ABI.
  2. Сборка динамического модуля под вашу установленную версию NGINX. Плюс — стопроцентная совместимость, минус — нужно один раз собрать.

Проверяем версию и возможности

nginx -V

Вы увидите версию и флаги сборки. Нам важно совпадение версий исходников при компиляции динамического модуля. Если используете готовый пакет модуля из того же репозитория, следите, чтобы версии совпадали.

Сборка динамического модуля (универсальный рецепт)

На Debian/Ubuntu:

apt-get update
apt-get install -y build-essential libpcre3-dev zlib1g-dev libssl-dev devscripts dpkg-dev
apt-get source nginx

Положите исходники otel‑модуля в каталог, например /usr/local/src/ngx_otel_module (получение исходников опускаем — используйте официальный источник конкретной версии модуля).

cd nginx-1.25.5
./configure --with-compat --add-dynamic-module=/usr/local/src/ngx_otel_module
make modules

Готовый .so обычно появится в objs/. Скопируйте его в директорию модулей NGINX и подключите:

cp objs/ngx_otel_module.so /etc/nginx/modules/

В /etc/nginx/nginx.conf добавьте загрузку модуля (строка должна быть вне блоков http/events):

load_module modules/ngx_otel_module.so;

В некоторых сборках имя файла и модуля может быть другим, например ngx_http_opentelemetry_module.so. Проверьте как называется артефакт вашей сборки.

Exporter по OTLP: настройка через переменные среды

Большинство реализаций otel‑модуля для NGINX используют стандартные OTEL_* переменные среды OpenTelemetry. Это удобно: единый способ сконфигурировать endpoint, протокол, sampling, ресурсы, таймауты. Настроим drop‑in для systemd, чтобы не трогать глобальные переменные в системе.

Drop‑in для nginx.service

Создайте файл /etc/systemd/system/nginx.service.d/otel.conf со следующим содержимым:

[Service]
Environment=OTEL_RESOURCE_ATTRIBUTES=service.name=nginx-front,service.version=1.25.5,deployment.environment=prod
Environment=OTEL_EXPORTER_OTLP_PROTOCOL=grpc
Environment=OTEL_EXPORTER_OTLP_ENDPOINT=127.0.0.1:4317
Environment=OTEL_EXPORTER_OTLP_TIMEOUT=5s
Environment=OTEL_TRACES_SAMPLER=parentbased_traceidratio
Environment=OTEL_TRACES_SAMPLER_ARG=0.05
Environment=OTEL_BSP_MAX_EXPORT_BATCH_SIZE=512
Environment=OTEL_BSP_MAX_QUEUE_SIZE=4096
Environment=OTEL_BSP_SCHEDULE_DELAY=2000
Environment=OTEL_BSP_EXPORT_TIMEOUT=5000
Environment=OTEL_METRICS_EXPORT_INTERVAL=10000
Environment=OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE=cumulative

Примените изменения и перезапустите NGINX:

systemctl daemon-reload
systemctl restart nginx

Здесь мы:

  • Описали ресурсные атрибуты (они попадут в каждый спан и метрику): service.name, service.version, deployment.environment. При необходимости добавьте service.namespace, host.name и др.
  • Выбрали протокол OTLP gRPC на 127.0.0.1:4317 — самый эффективный для локального Collector.
  • Задали sampling: parentbased_traceidratio c параметром 0.05 (5% новых корневых трасс; дочерние унаследуют решение).
  • Настроили Batch Span Processor (размер пакета, очередь, тайминги) и интервал экспорта метрик.

Если вам нужен OTLP/HTTP, замените протокол: OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf и endpoint на 127.0.0.1:4318. Всё остальное останется тем же.

Нужно ли включать трейсинг в nginx.conf

В зависимости от версии сборки otel‑модуль может начинать инструментирование сразу после загрузки (т. е. достаточно load_module и переменных среды). Некоторые сборки поддерживают явный «тумблер» на уровне http или server (например, директива включения трейсинга). Проще всего ориентироваться на поведение в вашей сборке:

  • Если спаны не появляются в Collector — проверьте логи NGINX на предмет ругани модуля и попробуйте включить режим отладки модуля или соответствующую директиву включения трейсинга.
  • В любом случае переменные среды OTEL остаются базовым способом указать exporter и sampling.

Collector: минимальная конфигурация для приёма OTLP

Запустите OpenTelemetry Collector рядом с NGINX и сконфигурируйте приемник OTLP. Пример otelcol.yaml:

receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318

processors:
  batch: {}
  resource:
    attributes:
      - key: service.instance.id
        action: upsert
        value: ${HOSTNAME}

exporters:
  logging:
    logLevel: info
  prometheus:
    endpoint: 0.0.0.0:9464
  otlp:
    endpoint: upstream-apm:4317
    tls:
      insecure: true

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [batch, resource]
      exporters: [logging, otlp]
    metrics:
      receivers: [otlp]
      processors: [batch, resource]
      exporters: [prometheus]

Такой Collector примет данные от NGINX, отдаст метрики в Prometheus‑совместимом виде и «прокинет» трассы во внешний APM по OTLP. Если вы выносите Collector в отдельный хост, удобно поднять его на VDS рядом с фронтами, чтобы держать низкие задержки OTLP. Если вы проксируете gRPC на периметре, загляните в разбор настроек в HAProxy — gRPC через HAProxy.

Пайплайн Collector: OTLP‑приёмник, процессоры, экспортеры Prometheus и APM

Маршрутизация и атрибуты: избегаем высокой кардинальности

Главная ловушка — атрибуты с бесконечным числом значений (например, http.target c реальным $uri и query‑строкой). Спаны с миллионами уникальных значений тяжело хранить и агрегировать. Решения:

  • Используйте логические «роуты» вместо реальных путей. На уровне NGINX это естественно: у нас уже есть location/map. Сопоставьте маршрутам понятные имена и отдавайте их как http.route (в зависимости от версии модуля атрибут можно задать через конфигурацию модуля или через Collector/processor).
  • Убирайте чувствительные данные: токены, e‑mail, телефоны. Не добавляйте их в атрибуты спанов.
  • Если часть URI всё же нужна, нормализуйте её в map и отдавайте «схему». Например, /product/123/product/{id}.

Пример нормализации на уровне NGINX

Даже без специальных директив модуля вы можете завести переменную для логического имени маршрута и использовать её в логах либо передавать дальше в Collector процессором:

map $uri $route_name {
  default other;
  ~^/api/v1/items/\d+$ api.v1.items.id;
  ~^/auth/login$ auth.login;
}

server {
  listen 80;
  # Пример: передадим route как заголовок (коллектор может прочитать и переписать его в атрибут http.route)
  location / {
    proxy_set_header X-Route-Name $route_name;
    proxy_pass http://app;
  }
}

Далее в Collector через attributes processor можно переименовать X-Route-Name в http.route и удалить сам заголовок, чтобы не уходил в бэкенд.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Пропагация trace‑контекста к upstream

Если otel‑модуль включён, он, как правило, сам инжектирует W3C Trace Context к upstream. Но если вы только переходите и хотите сохранить совместимость, допускается временное ручное прокидывание:

proxy_set_header traceparent $http_traceparent;
proxy_set_header tracestate $http_tracestate;

Это не генерирует новый контекст, если его не было у клиента, но сохранит связность там, где контекст уже приходит извне (например, из другого сервисного узла).

TLS к Collector и безопасность

Даже если Collector крутится локально, рано или поздно вы вынесете его в отдельный хост/кластер. Подготовьтесь заранее:

  • Включите TLS на уровне OTLP (и на gRPC, и на HTTP). Проверьте поддержку TLS в вашем билде модуля и задайте сертификаты и доверенные корни так, как это предусмотрено его конфигурацией или переменными среды.
  • Отключите экспорт на «сырой» внешний адрес, если Collector доступен по localhost — это снижает поверхность атаки.
  • Не добавляйте PII в атрибуты: убирайте токены и идентификаторы пользователей из URI, заголовков и т. д.

Производительность и оверхед

Оверхед от трейсинга в NGINX умеренный, если:

  • Экспорт — только на локальный Collector по gRPC,
  • Включён batch‑режим с адекватными размерами и задержками,
  • Sampling на уровне 1–10% для «тяжёлых» фронтов.

Правила практической эксплуатации:

  • Выставляйте sampling как parentbased_traceidratio, а фронту — 1–5%. Для критичных путей можно поднимать sampling через правила (делается на стороне Collector с помощью tail‑based sampling, если нужен умный отбор по статусу/латентности).
  • Проводите нагрузочное тестирование до и после включения, фиксируйте разницу CPU/mem/latency. На типичных профилях увеличение CPU в пределах нескольких процентов и небольшой рост latency в пределах десятков миллисекунд на «холодной» очереди.
  • Разносите экспорт метрик и трасс по разным потокам/очередям, если это поддерживается вашей сборкой.

Диагностика: «спаны не доходят»

  • Порт: 4317/4318 закрыты firewall — проверьте правила для localhost и внешних интерфейсов.
  • Версии: модуль собран не под ту версию NGINX — в ошибках при старте увидите undefined symbol. Пересоберите модуль под точную версию.
  • Переменные среды: systemd drop‑in не подхватился — проверьте systemctl cat nginx, затем systemctl daemon-reload и рестарт.
  • Sampling: поставили 0% (или оно так унаследовалось) — временно задайте OTEL_TRACES_SAMPLER=always_on для проверки.
  • Collector: не поднят или упал. Для первичной отладки включите logging exporter в Collector и смотрите входящие спаны, чтобы понять, доезжает ли трафик.
  • TLS: неверные корни, SNI, истёкшие сертификаты — проверьте настройки TLS на OTLP‑соединении и журналах Collector.

Метрики NGINX через OpenTelemetry

Otel‑модуль умеет отправлять и метрики, что полезно, если вы хотите уйти от scrape‑модели. Пара рекомендаций:

  • Темпоральность: большинство хранилищ ждут cumulative. Если ваш стек предпочитает delta — переключите через OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE.
  • Агрегация гистограмм: при необходимости регулируйте набор bucket’ов на стороне Collector (metrics pipeline).
  • Кардинальность: не размечайте метрики по «дикому» http.target. Ограничьтесь http.route, http.method, http.status_code, server.address.

Пошаговый чек‑лист внедрения

  1. Выберите способ установки otel‑модуля (готовый пакет или сборка).
  2. Загрузите модуль в nginx.conf через load_module.
  3. Поднимите локальный Collector с приёмником OTLP (gRPC и/или HTTP).
  4. Пропишите OTEL_* переменные среды для nginx.service (endpoint, протокол, ресурсы, sampling, batch).
  5. Перезапустите NGINX, убедитесь что Collector видит входящие спаны и метрики.
  6. Нормализуйте маршруты и удалите чувствительные атрибуты на стороне Collector.
  7. Проведите нагрузочное тестирование и закрепите параметры batch/sampling.
  8. Вынесите Collector или сделайте HA, добавьте TLS/аутентификацию наружу.

Частые практические вопросы

Можно ли оставить scrape‑метрики, а трассы — через OTLP?

Да. Collector может одновременно поднимать OTLP‑приёмник для трасс и отдавать метрики наружу через Prometheus‑endpoint (exporters.prometheus). Это удобный гибрид для постепенной миграции.

Как проставить service.name, если модуль его не выставляет?

Укажите его в OTEL_RESOURCE_ATTRIBUTES — это самый переносимый путь: service.name=nginx-front. Дополнительно настройте service.namespace, если у вас несколько логических доменов.

Нужно ли дублировать trace‑id в access‑логах?

Для операционных разборов иногда удобно иметь trace_id в логе. Если ваша сборка модуля экспонирует переменную с текущим trace‑id, добавьте её в формат лога. Если нет — на время миграции можно прокидывать traceparent от клиента и вынимать trace‑id регуляркой в map.

Как безопасно отключить трейсинг, если что‑то пошло не так?

Самый быстрый способ — задать OTEL_TRACES_SAMPLER=always_off и перезапустить NGINX. Для полного отката — удалить строку load_module и сделать nginx -t плюс reload.

Итоги

Инструментирование NGINX через OpenTelemetry — прямой и «чистый» путь к полным трассам и метрикам периметра: без парсеров логов и зоопарка экспортеров. Практически значимо две вещи: держите OTLP‑экспорт локальным (Collector на том же хосте) и строго управляйте кардинальностью атрибутов, особенно http.target и кастомных тегов. Тогда вы получите воспроизводимую картину задержек по каждому участку пути — от клиента до бэкенда — и сможете решать реальные проблемы производительности и надёжности, а не охотиться за «призраками» в метриках.

Поделиться статьей

Вам будет интересно

etcd на VDS: практический гайд по snapshot, defrag и restore (в т.ч. для Kubernetes) OpenAI Статья написана AI (GPT 5)

etcd на VDS: практический гайд по snapshot, defrag и restore (в т.ч. для Kubernetes)

Надёжный backup для etcd — основа живучести Kubernetes и сервисов конфигурации. Разбираем, как снимать snapshot, когда делать comp ...
Tailscale на VDS: ACL, exit node и стабильный внешний IP OpenAI Статья написана AI (GPT 5)

Tailscale на VDS: ACL, exit node и стабильный внешний IP

Разворачиваем Tailscale на VDS и превращаем его в управляемый exit node со строгими ACL и стабильным внешним IP. Пошагово разберём ...
Postfix milter: OpenDMARC, OpenDKIM и Rspamd — рабочая связка для подписи, валидации и антиспама OpenAI Статья написана AI (GPT 5)

Postfix milter: OpenDMARC, OpenDKIM и Rspamd — рабочая связка для подписи, валидации и антиспама

Практическое руководство по интеграции OpenDKIM, OpenDMARC и Rspamd в Postfix через milter. Разберём архитектуру, порядок milters, ...