OpenTelemetry bridge: APISIX → otel-collector → Elasticsearch APM

Published: 2026-04-13

APISIX отправляет трейсы через OTLP/HTTP. Elasticsearch APM Server принимает трейсы через OTLP/gRPC. Транспорты несовместимы. OpenTelemetry Collector посередине решает эту проблему.


В чём проблема

Плагин opentelemetry в APISIX отправляет спаны на OTLP/HTTP-эндпоинт (порт 4318). Elastic APM Server принимает только OTLP/gRPC (порт 8200 или 4317). Без адаптера трейсы от APISIX до Kibana APM не доходят.


Архитектура

APISIX plugin
  │ OTLP/HTTP :4318
  ▼
otel-collector (Kubernetes Deployment)
  │ OTLP/gRPC :8200
  ▼
APM Server → Elasticsearch → Kibana APM UI

HelmRelease для otel-collector

yamlapiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
  name: otel-collector
  namespace: elasticsearch
spec:
  chart:
    spec:
      chart: opentelemetry-collector
      version: "0.97.0"
      sourceRef:
        kind: HelmRepository
        name: open-telemetry
        namespace: flux-system
  values:
    fullnameOverride: otel-collector    # критично — см. ниже
    mode: deployment
    replicaCount: 1
    config:
      receivers:
        otlp:
          protocols:
            http:
              endpoint: 0.0.0.0:4318
            grpc:
              endpoint: 0.0.0.0:4317
      exporters:
        otlp/elastic:
          endpoint: "apm-server.elasticsearch.svc.cluster.local:8200"
          tls:
            insecure: true
      service:
        pipelines:
          traces:
            receivers: [otlp]
            exporters: [otlp/elastic]
          metrics:
            receivers: [otlp]
            exporters: [otlp/elastic]
          logs:
            receivers: [otlp]
            exporters: [otlp/elastic]

Почему fullnameOverride критичен

Плагин opentelemetry в APISIX резолвит адрес коллектора через DNS. Если Helm-чарт генерирует имя вроде otel-collector-opentelemetry-collector (по умолчанию), настроенный адрес otel-collector.elasticsearch.svc.cluster.local:4318 не резолвится.

fullnameOverride: otel-collector фиксирует имя Service как otel-collector. Без этого APISIX молча отбрасывает спаны — в логах при этом ни одной ошибки.


Конфигурация плагина APISIX

ApisixGlobalRule включает плагин на всех маршрутах:

yamlapiVersion: apisix.apache.org/v2
kind: ApisixGlobalRule
metadata:
  name: opentelemetry
  namespace: ingress-apisix
spec:
  plugins:
    - name: opentelemetry
      enable: true
      config:
        sampler:
          name: always_on
        collector:
          address: "otel-collector.elasticsearch.svc.cluster.local:4318"
          request_timeout: 3
        additional_attributes:
          - apisix_service_id
          - apisix_balancer_ip
          - remote_addr
          - upstream_addr
          - upstream_status
          - upstream_response_time

Использовать полный FQDN для адреса коллектора. Короткие DNS-имена (otel-collector.elasticsearch.svc) периодически не резолвятся в Lua DNS-резолвере APISIX.

additional_attributes добавляет метаданные APISIX к каждому спану — решения балансировщика, IP upstream, время ответа. В Kibana APM они отображаются как пользовательские атрибуты и помогают при отладке балансировки.


APM Server

APM Server работает в namespace elasticsearch:

yamlvalues:
  apmConfig:
    apm-server.yml: |
      apm-server:
        host: "0.0.0.0:8200"
      output.elasticsearch:
        hosts: ["http://dev-master.elasticsearch:9200"]
        username: "elastic"
        password: "${ELASTIC_PASSWORD}"
      apm-server.auth.anonymous:
        enabled: true
        allow_service: []

Принимает и OTLP/gRPC, и нативный APM-протокол на порту 8200.


Просмотр трейсов в Kibana

После запуска пайплайна в Kibana APM доступны:

  • Service map — какие сервисы вызывают какие эндпоинты, с тепловой картой задержек
  • Transaction traces — полные спаны от APISIX до upstream с разбивкой по времени
  • Error rate и перцентили задержек по сервису и эндпоинту

Атрибут apisix_service_id связывает каждый трейс с конкретным маршрутом APISIX — удобно коррелировать алерты о задержках с конкретными API.


Валидация пайплайна

bash# Проверить, что otel-collector принимает спаны
kubectl logs -n elasticsearch deployment/otel-collector \
  --context=dev-k8s | grep -i "traces\|spans"

# Проверить, что APM Server получает данные от коллектора
kubectl logs -n elasticsearch deployment/apm-server \
  --context=dev-k8s | grep "Publish"

# Сгенерировать тестовый трейс (любой запрос через APISIX)
curl -H "Host: myapp.dev.example.com" http://172.16.57.193/ -v

Проверить метрики otel-collector:

bashkubectl port-forward -n elasticsearch svc/otel-collector 8888:8888
curl http://localhost:8888/metrics | grep otelcol_receiver_accepted

Частые проблемы

Спаны не появляются в Kibana — проверить по цепочке: APISIX → otel-collector → APM Server. Использовать kubectl logs на каждом шаге.

DNS-ошибка в APISIX — использовать полный FQDN service.namespace.svc.cluster.local.

Забыт fullnameOverride — Helm генерирует длинное имя, APISIX не может его разрешить, спаны молча отбрасываются.

Ошибки TLS в APM Server — установить tls.insecure: true в экспортере, если APM Server без TLS.