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.