OpenTelemetry OpenTelemetry

Usa el OpenTelemetry Operator para Collectors y auto-instrumentación

Declara Collectors e instrumentación como recursos de Kubernetes e inyecta agentes con anotaciones de pods.

15 min Avanzado

El OpenTelemetry Operator gestiona dos cosas como recursos de Kubernetes: Collectors (un objeto OpenTelemetryCollector) y auto-instrumentación (un objeto Instrumentation más anotaciones de pods que le dicen al Operator que inyecte un agente). Los equipos de aplicación obtienen telemetría añadiendo una anotación, no editando Dockerfiles, y los equipos de plataforma mantienen los ajustes en un solo lugar en Git.

Instala el Operator

El Operator usa admission webhooks, que necesitan certificados TLS. La ruta más simple es cert-manager, que el chart espera por defecto. Sin cert-manager, deja que Helm genere un certificado autofirmado:

helm repo add open-telemetry https://open-telemetry.github.io/opentelemetry-helm-charts
helm repo update

helm install my-opentelemetry-operator open-telemetry/opentelemetry-operator \
  --namespace opentelemetry-operator-system --create-namespace \
  --set "manager.collectorImage.repository=otel/opentelemetry-collector-k8s" \
  --set admissionWebhooks.certManager.enabled=false \
  --set admissionWebhooks.autoGenerateCert.enabled=true

Con cert-manager ya instalado, puedes dejar los ajustes de certificados en sus valores predeterminados, o hacer referencia a tu propio emisor mediante admissionWebhooks.certManager.issuerRef. Fija la versión del chart con --version, y pon los valores en un archivo o en un HelmRelease de Flux en lugar de flags --set.

Declara un Collector

apiVersion: opentelemetry.io/v1beta1
kind: OpenTelemetryCollector
metadata:
  name: demo
  namespace: observability
spec:
  mode: deployment        # deployment, daemonset, statefulset o sidecar
  replicas: 2
  config:
    receivers:
      otlp:
        protocols:
          grpc:
            endpoint: 0.0.0.0:4317
          http:
            endpoint: 0.0.0.0:4318
    processors:
      memory_limiter:
        check_interval: 1s
        limit_percentage: 80
        spike_limit_percentage: 20
      batch: {}
    exporters:
      debug: {}
    service:
      pipelines:
        traces:
          receivers: [otlp]
          processors: [memory_limiter, batch]
          exporters: [debug]

El bloque config es el mismo YAML del Collector que has estado escribiendo, incrustado en el recurso. El Operator crea la carga de trabajo y un Service llamado <nombre>-collector (aquí demo-collector) que expone los puertos que usan tus receivers. Los valores de mode disponibles se corresponden con los patrones de la guía de despliegue: daemonset para agentes, deployment para gateways y sidecar para un Collector inyectado en los pods de aplicación. Comprueba la versión del CRD disponible en tu clúster (kubectl get crd opentelemetrycollectors.opentelemetry.io), ya que la versión de la API ha cambiado entre releases.

Declara los ajustes de instrumentación

Un recurso Instrumentation contiene los ajustes del SDK que el Operator inyecta en los pods anotados:

apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
  name: demo-instrumentation
  namespace: webapp
spec:
  exporter:
    endpoint: http://demo-collector.observability.svc.cluster.local:4318
  propagators:
    - tracecontext
    - baggage
  sampler:
    type: parentbased_traceidratio
    argument: "0.25"
  java:
    env:
      - name: OTEL_INSTRUMENTATION_COMMON_DEFAULT_ENABLED
        value: "true"

Detalles importantes:

  • exporter.endpoint toma por defecto http://localhost:4317 si se omite, lo que normalmente no entrega nada. Defínelo siempre con el Service de tu Collector.
  • Para un Collector en otro namespace, usa el nombre DNS completo, <servicio>.<namespace>.svc.cluster.local.
  • Los ejemplos documentados usan el puerto 4318 (HTTP) para .NET, Go, Java y Python, y 4317 (gRPC) para Node.js. Haz coincidir el puerto con el protocolo que usa el agente del lenguaje.
  • Las variables de entorno específicas de cada lenguaje van bajo spec.<lenguaje>.env, como spec.java.env o spec.python.env.

Crea el Instrumentation antes que la aplicación. El Operator inyecta el agente cuando se crea un pod. Si el recurso todavía no existe, el pod arranca sin el init container y tienes que reiniciarlo.

Activa las cargas de trabajo con anotaciones

Añade una anotación a la plantilla del pod de un Deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: checkout
  namespace: webapp
spec:
  selector:
    matchLabels: { app: checkout }
  template:
    metadata:
      labels: { app: checkout }
      annotations:
        instrumentation.opentelemetry.io/inject-java: "true"
    spec:
      containers:
        - name: checkout
          image: myorg/checkout:1.4.2

La anotación por lenguaje:

LenguajeAnotación
Javainstrumentation.opentelemetry.io/inject-java: "true"
Pythoninstrumentation.opentelemetry.io/inject-python: "true"
Node.jsinstrumentation.opentelemetry.io/inject-nodejs: "true"
.NETinstrumentation.opentelemetry.io/inject-dotnet: "true"
Goinstrumentation.opentelemetry.io/inject-go: "true" (más la anotación del ejecutable objetivo)
Solo ajustes del SDKinstrumentation.opentelemetry.io/inject-sdk: "true"

El valor puede ser "true" (usa el Instrumentation de este namespace), el nombre de uno ("my-instrumentation"), un nombre calificado con namespace ("other-ns/my-instrumentation") o "false". Pon la anotación en un namespace para instrumentar todas las cargas de trabajo de él.

Anotaciones relacionadas que usarás:

  • instrumentation.opentelemetry.io/container-names: "app,worker" elige qué contenedores instrumentar. Por defecto solo se instrumenta el primero.
  • resource.opentelemetry.io/service.name: checkout define atributos de recurso como el nombre del servicio. Otros incluyen service.version y deployment.environment.name.
  • instrumentation.opentelemetry.io/inject-sdk: "true" inyecta solo las variables de entorno, para aplicaciones que ya incluyen un SDK.
  • Un solo contenedor no puede tener más de un lenguaje inyectado. Las configuraciones multicontenedor y multilenguaje necesitan el feature flag enable-multi-instrumentation y anotaciones de nombres de contenedor por lenguaje.
  • Go requiere el feature gate enable-go-instrumentation, la anotación otel-go-auto-target-exe (o el ajuste OTEL_GO_AUTO_TARGET_EXE) y un sidecar privilegiado, así que revisa antes las implicaciones de seguridad.

Aplica y verifica

kubectl apply -f collector.yaml -f instrumentation.yaml
kubectl apply -f checkout-deployment.yaml

kubectl get opentelemetrycollectors,instrumentations -A
kubectl get pod -n webapp -l app=checkout -o jsonpath='{.items[0].spec.initContainers[*].name}'; echo
kubectl logs -n observability deploy/demo-collector | grep -i 'service.name'

Un init container llamado opentelemetry-auto-instrumentation en el pod de la aplicación significa que la inyección funcionó. Genera algo de tráfico, y el exporter debug del Collector debería imprimir spans con el nombre de tu servicio.

Solución de problemas

  1. ¿Está el recurso Instrumentation? kubectl describe otelinst -n <namespace>.
  2. ¿Errores del Operator? Lee los logs del contenedor manager en el namespace del Operator.
  3. ¿Se creó antes que la aplicación? Si no, reinicia el Deployment para que el pod se recree y se inyecte. Comprueba kubectl get events -n <namespace> para ver el init container.
  4. ¿Es correcta la anotación? Debe estar en spec.template.metadata.annotations, y el lenguaje debe coincidir con el de la aplicación.
  5. ¿Es correcto el endpoint? Un protocolo o puerto incorrectos, o un nombre de Service corto entre namespaces, no envía nada en silencio.

Cuándo preferir el Operator

Úsalo cuando muchos equipos despliegan en el clúster y quieres que la telemetría sea opcional mediante anotación, con los ajustes gestionados de forma central. Usa el chart de Helm simple cuando solo necesites un Collector y gestiones la configuración del SDK en los manifiestos de cada aplicación. El Operator y el chart pueden coexistir, pero no gestiones el mismo Collector con ambos.

Guías populares