Plataformas de telemetría gestionadas para cargas de trabajo en Kubernetes

Resumen

Este blueprint ofrece una guía estratégica para las organizaciones que buscan adoptar prácticas de Platform Engineering para facilitar la adopción de las herramientas y los estándares de OpenTelemetry en sus equipos de ingeniería. Esto incluye el uso de SDKs, bibliotecas de instrumentación, patrones de configuración y arquitecturas de Collector para ofrecer plataformas de telemetría gestionadas de forma centralizada, combinadas con herramientas de autoservicio diseñadas para consumirse “as-a-service”.

Está dirigido a organizaciones que operan en entornos de nube y Kubernetes, que desean ofrecer una plataforma de telemetría coherente, escalable y gobernada en cargas de trabajo que son propiedad de equipos de producto altamente autónomos, logrando los siguientes resultados:

  • Configuración coherente de SDK e instrumentación, que mejora el tiempo de obtención de valor (time-to-value) al facilitar la adopción de estándares específicos de la organización en todas las cargas de trabajo, reduciendo la carga cognitiva de los equipos de producto.
  • Convenciones semánticas cohesivas que permiten la correlación de telemetría entre señales, aplicaciones y dominios, desde el lado del cliente hasta la infraestructura, proporcionando telemetría de alta calidad que puede utilizarse en análisis manuales o automáticos.
  • Eliminación de la proliferación descontrolada de configuraciones de Collector, reduciendo el esfuerzo operativo manual mediante la consolidación de las canalizaciones de telemetría.
  • Canalizaciones de ingesta resilientes, escalables y fiables para todas las señales de telemetría, evitando puntos únicos de fallo.
  • Gobernanza centralizada de la telemetría y optimización de datos para reducir los costos operativos y las emisiones de carbono, minimizando los requisitos de almacenamiento, transferencia de red y cómputo del procesamiento de telemetría.
  • Canalizaciones de telemetría preparadas para el futuro que protegen a los equipos de producto de los cambios en el backend de observabilidad subyacente, permitiendo migraciones de datos o estrategias multiproveedor con cambios mínimos en la instrumentación de la aplicación o en la infraestructura de recopilación.

Contexto

A medida que las organizaciones aumentan la velocidad de adopción de los estándares cloud native y las prácticas modernas de entrega de software, suelen adoptar modelos federados en los que los equipos, o unidades de negocio, operan con alta autonomía y son responsables de todo el Ciclo de Vida de Desarrollo de Software (SDLC) de sus sistemas, desde el diseño hasta la operación del software en producción.

Este modelo de «tú lo construyes, tú lo operas» está diseñado para potenciar la entrega de producto, pero puede crear de forma inadvertida prácticas fragmentadas de gestión de servicios y panoramas de observabilidad desordenados que no logran aprovechar los beneficios de OpenTelemetry y las herramientas modernas de observabilidad. Los equipos de producto priorizan la entrega de funcionalidades sobre los Requisitos No Funcionales (NFR), como la instrumentación de telemetría, y ven estas tareas como una carga para sus objetivos de entrega.

Para abordar esto, las organizaciones están adoptando ampliamente modelos de Platform Engineering cloud native para reducir la carga cognitiva y abstraer la complejidad. Al tratar la observabilidad como un producto de plataforma interno y curado, las organizaciones pueden ofrecer un camino allanado, o golden path, que garantiza una observabilidad contextual de alta calidad con una fricción mínima, permitiendo a los equipos seguir centrados en instrumentar conceptos específicos de su dominio que resulta imposible capturar en la telemetría lista para usar.

Retos comunes

Las organizaciones que operan en estos entornos federados y distribuidos suelen enfrentarse a un conjunto particular de retos que dificultan una observabilidad eficaz y la madurez cloud native.

1. Configuración inconsistente y baja adopción de estándares organizacionales

En entornos donde los equipos de producto operan con autonomía, pueden coexistir distintas formas de configurar aplicaciones y servicios individuales para la observabilidad, aun operando bajo una capa de cómputo compartida. Esto incluye la configuración de los SDKs de OpenTelemetry para las aplicaciones, la configuración de paquetes y bibliotecas de instrumentación, o la decisión de cómo propagar el contexto de observabilidad desde y hacia sus dependencias.

Las organizaciones pueden contar con un conjunto de estándares de ingeniería documentados que desean que todos los ingenieros sigan, pero a menudo dependen de la implementación manual de estos estándares por parte de cada equipo individual, incluyendo cambios de configuración y a nivel de código. Los equipos suelen tratar esto como algo secundario, que no forma parte del proceso de diseño del software, y centrado en una aplicación concreta sin considerar el sistema distribuido en su conjunto de forma holística.

---
title: "Figura 1: Silos debido a la falta de convenciones semánticas coherentes y propagación de contexto."
config:
  flowchart:
    curve: basis
---
flowchart LR
  subgraph K8sNode["Nodo de Kubernetes"]
    direction TB
    AppA["📦 App A"]:::node
    AppB["📦 App B"]:::node
    Collector["🔀 Collector"]:::node
  end

  subgraph TracesDB["🧵️Backend de trazas"]
    direction LR
    TraceX[("🧵 Traza X")]:::node
    TraceY[("🧵 Traza Y")]:::node
  end

  subgraph MetricsDB["📈 Backend de métricas"]
    Metrics[("📈 Métricas del contenedor")]:::node
  end

  User["👤 Usuario"]:::node

  User L_User_AppA@-- Solicitud entrante --> AppA
  AppA L_AppA_AppB@-. "Dependencia<br>(contexto de traza roto)" .-x AppB
  TracesDB L_TracesDB_MetricsDB@x-. "Correlación rota<br>(faltan atributos k8s.*)" .-x MetricsDB
  AppA L_AppA_TraceX@== Spans ==> TraceX
  AppB L_AppB_TraceY@== Spans ==> TraceY
  Collector L_Collector_MetricsDB@== "Métricas<br>(k8s.pod.name=app-...)" ==> MetricsDB

  classDef node fill:#ffffff, stroke:#818cf8, stroke-width:2px, color:#6b7280
  style K8sNode fill:#eef2ff, stroke:#818cf8, stroke-width:2px, color:#818cf8
  style TracesDB fill:#eef2ff, stroke:#818cf8, stroke-width:2px, color:#818cf8
  style MetricsDB fill:#eef2ff, stroke:#818cf8, stroke-width:2px, color:#818cf8
  linkStyle 0 stroke:#7dd3fc, fill:none, stroke-width:3px
  linkStyle 1 stroke:#fca5a5, fill:none, stroke-width:3px
  linkStyle 2 stroke:#fca5a5, fill:none, stroke-width:3px
  linkStyle 3,4,5 stroke:#a3e635, fill:none, stroke-width:3px

  L_User_AppA@{ animation: slow }
  L_AppA_AppB@{ animation: slow }
  L_TracesDB_MetricsDB@{ animation: slow }
  L_AppA_TraceX@{ animation: fast }
  L_AppB_TraceY@{ animation: fast }
  L_Collector_MetricsDB@{ animation: fast }

Esto conduce a:

  • Convenciones Semánticas inconsistentes: la telemetría carece de atributos comunes de recurso (por ejemplo, service.version, k8s.cluster.name, example.cost.center), lo que rompe la correlación entre distintas señales, aplicaciones y capas del sistema, y limita la utilidad de los datos de observabilidad para el análisis automático.
  • Silos de contexto: sin una propagación de contexto coherente (por ejemplo, W3C Trace Context) integrada en cada SDK, las trazas distribuidas se rompen en los límites entre servicios, lo que hace imposible vincular las regresiones de rendimiento del backend con el impacto en el negocio de cara al cliente.
  • Fragmentación de versiones de SDK: versiones muy distintas de los SDKs de OpenTelemetry ejecutándose en producción, lo que genera problemas de mantenimiento y seguridad.
  • Alta carga cognitiva: los desarrolladores deben configurar manualmente los SDKs y los paquetes de instrumentación para cada nuevo servicio, lo que aumenta el esfuerzo manual y el riesgo de una configuración incorrecta.
  • Menor velocidad: cualquier cambio en los estándares de ingeniería relacionados con la instrumentación de telemetría, o cualquier cambio en el backend de observabilidad subyacente, como migraciones de datos o de protocolo, genera fricción y reduce la velocidad general de la organización, ya que la adopción de tecnología termina viéndose obstaculizada por la implementación manual.

2. Proliferación descontrolada de configuraciones de Collector entre clústeres

A medida que la adopción de OpenTelemetry crece en escala, y las organizaciones despliegan en decenas o cientos de clústeres de Kubernetes, gestionar manualmente las configuraciones individuales del OpenTelemetry Collector en estos entornos genera una carga de mantenimiento. Esto resulta especialmente difícil en organizaciones donde distintos equipos gestionan distintos despliegues de Collector.

Esto conduce a:

  • Desviación de configuración: distintos clústeres terminan con reglas de parseo, lógica de filtrado y configuraciones de endpoint diferentes, lo que provoca un comportamiento impredecible de la telemetría.
  • Falta de separación de responsabilidades: no existe una distinción clara entre los distintos tipos de procesamiento de telemetría realizados en las diferentes capas de Collectors (por ejemplo, dónde transformar, dónde muestrear), lo que puede generar datos inconsistentes o incompletos.
  • Esfuerzo manual: los equipos de plataforma dedican una cantidad excesiva de tiempo a tareas de configuración repetitivas y actualizaciones manuales, en lugar de construir soluciones escalables.
  • Despliegues poco fiables: sin despliegues auditables y controlados por versiones, aplicar una corrección o una nueva configuración en toda la flota se vuelve muy arriesgado y propenso a errores.

3. Canalizaciones de datos no optimizadas para los requisitos de los datos de observabilidad

En algunos modelos de instrumentación heredados, las aplicaciones o los agentes de instrumentación suelen exportar la telemetría directamente a los backends de telemetría. Este modelo carece de una forma de procesar y transformar la telemetría entre la aplicación y el backend, lo que reduce la soberanía de los datos. También puede añadir complejidad adicional si el backend es un proveedor externo, o cualquier endpoint que requiera tráfico público o autenticación. Gestionar credenciales en miles de aplicaciones puede ser difícil, y los problemas esporádicos de conectividad de red entre un único exportador y un endpoint público pueden provocar interrupciones del servicio.

Por el contrario, en entornos donde las canalizaciones de datos están centralizadas, los requisitos de los datos de telemetría a menudo se mezclan con los de otros tipos de datos. Esto puede derivar en soluciones optimizadas para la completitud (por ejemplo, el registro de auditoría o los informes de datos financieros) en lugar de transformaciones sensibles al contexto y un procesamiento de baja latencia. Esto aumenta el tiempo que transcurre entre la emisión de los datos y la obtención de información accionable, necesaria para mantener operaciones fiables.

Esto conduce a:

  • Puntos únicos de fallo: la salida directa a internet desde cientos de aplicaciones individuales priva a la organización de la gobernanza de red centralizada y de exportaciones balanceadas.
  • Latencia y valor operativo: en última instancia, los datos de observabilidad obsoletos son casi tan inútiles como no tener datos de observabilidad. Las canalizaciones de logs demasiado complejas pueden introducir un retraso significativo, dejando inútiles las alertas operativas en tiempo real durante un incidente importante.
  • Falta de control central: los equipos de plataforma no pueden redirigir fácilmente los datos, cambiar de proveedor o aplicar políticas de red globales cuando las configuraciones están profundamente incrustadas en aplicaciones individuales.

4. Falta de gobernanza de la telemetría y bajo ROI

Sin una gobernanza centralizada y una adopción medible de los estándares de observabilidad, los equipos autónomos pueden generar grandes cantidades de datos de bajo valor, reduciendo la relación señal-ruido. Las señales de OpenTelemetry a menudo no se usan para su propósito previsto, lo que en última instancia dificulta su mantenimiento para los equipos de plataforma (por ejemplo, tener que garantizar consultas rápidas y precisas sobre días o semanas de logs individuales simplemente para calcular el número de solicitudes de un determinado servicio). A medida que el tráfico crece y aumenta el volumen de telemetría, los equipos responsables de la observabilidad no cuentan con una forma escalable de garantizar la calidad de los datos en todo su panorama.

Esto conduce a:

  • Problemas de calidad de datos no atribuidos: al no aplicarse convenciones semánticas coherentes, los equipos de plataforma no pueden asociar el gasto en telemetría o la calidad de los datos con unidades de negocio o equipos de ingeniería específicos.
  • Tipos de datos ineficientes: las organizaciones incurren en altos costos de almacenamiento e indexación para logs sin procesar u otras señales cuando no se usan para su propósito previsto, a la vez que reducen la calidad general de la información extraída de los datos de observabilidad.
  • Costos innecesarios: el aumento de los costos asociados al almacenamiento de datos, la salida de red o la ingesta en un backend determinado, derivados de datos que no siempre mejoran la información necesaria para operar los sistemas de forma fiable.
  • Emisiones de carbono: el procesamiento de datos de bajo valor puede perjudicar el cumplimiento de los objetivos de software verde, incluidas las emisiones de alcance 3 derivadas del carbono incorporado en los dispositivos necesarios para la recuperación rápida de datos de observabilidad, como los SSD.
  • Alta carga cognitiva: los grandes volúmenes de datos no solo generan costos innecesarios, sino que también pueden aumentar el ruido, obligando a usuarios y agentes a filtrar datos de baja calidad para encontrar la telemetría relevante.

5. Baja observabilidad y eficiencia operativa de los SDKs y las canalizaciones de datos

Uno de los retos de operar SDKs y Collectors de OpenTelemetry en producción es identificar si, y cuándo, la configuración predeterminada aplicada a aspectos como el encolado, los reintentos o la agrupación (batching) de los datos de telemetría no es óptima para un entorno concreto. Los valores predeterminados razonables de OpenTelemetry pueden no ser adecuados ni para implementar un enfoque más eficiente en el uso de recursos, ni para lograr mayores garantías de fiabilidad. Esto puede depender de los patrones arquitectónicos en uso; por ejemplo, exportar a un endpoint de clúster local puede requerir menos almacenamiento en búfer que un endpoint público de internet.

Esto conduce a:

  • Pérdidas silenciosas de datos y fallos de exportación: las exportaciones de datos sufren fallos al exportar a los backends o a los Collectors, lo que finalmente descarta datos, sin que esos errores se observen o generen alertas.
  • Uso innecesario de recursos: los operadores sobreaprovisionan recursos en los SDKs y los Collectors, aumentando el uso de recursos y afectando potencialmente la sobrecarga de rendimiento y el costo.

Directrices generales

1. Centralizar la configuración predeterminada y extensible para SDKs y paquetes de instrumentación

Retos abordados: 1, 4 | Acciones de implementación: 1, 2

Recomendamos que los equipos responsables de las herramientas de observabilidad mantengan un conjunto de recursos (ver Acción 1) para proporcionar una configuración básica y lista para usar para los SDKs y las bibliotecas de instrumentación. El objetivo es que las aplicaciones desplegadas en un clúster de Kubernetes emitan un nivel básico de telemetría y propaguen el contexto desde y hacia sus dependencias, con una intervención mínima por parte de los responsables de las aplicaciones, por ejemplo, como máximo añadiendo una anotación o llamando a una biblioteca interna compartida.

Los equipos de plataforma deben garantizar que esta configuración base siga siendo extensible, permitiendo a los responsables de las aplicaciones controlar distintos aspectos del SDK (por ejemplo, el tamaño de los búferes, los reintentos del exportador) y de las bibliotecas de instrumentación, para satisfacer los requisitos específicos de sus aplicaciones.

Al implementar esta directriz, las organizaciones pueden esperar lograr:

  • Estándares organizacionales cohesivos: los estándares específicos de la organización (por ejemplo, atributos de recurso, endpoint del exportador, etc.) se aplican automáticamente en toda la pila.
  • Propagación de contexto coherente: el Trace Context se propaga entre servicios usando configuraciones de propagador compatibles.
  • Menor carga cognitiva: los responsables de las aplicaciones pueden abstraerse de la configuración de bajo nivel, como la relacionada con la configuración del SDK de OpenTelemetry.
  • Mantenimiento más sencillo: se minimiza el esfuerzo necesario para adoptar estándares de ingeniería y buenas prácticas en observabilidad, ya que los nuevos estándares pueden implementarse mediante actualizaciones de versión de las herramientas internas.

2. Establecer una propiedad compartida para la producción de telemetría

Retos abordados: 4, 5 | Acciones de implementación: 1, 2, 5

Para equilibrar la gobernanza y la autonomía, los equipos de plataforma que operan en los entornos descritos en este blueprint deben aplicar el “shift left” en la instrumentación, garantizando que los responsables de las aplicaciones tengan control total y propiedad sobre la telemetría emitida por sus aplicaciones. Las configuraciones predeterminadas mencionadas en la Directriz 1 deben garantizar la procedencia de los datos, incluyendo atributos técnicos (por ejemplo, clúster, deployment, pod) e información organizacional (por ejemplo, equipo, dominio de negocio), con el objetivo de que sea trivial identificar el origen de la telemetría y el equipo propietario.

Los principios de diseño de clientes de OpenTelemetry establecen una separación clara entre la API, que por defecto es una implementación no-op, y el SDK, que proporciona una implementación de esa API cuando se registra. Esto ofrece una separación clara de responsabilidades y permite a los responsables de las aplicaciones apoyarse únicamente en la API de OpenTelemetry, centrando sus esfuerzos en enriquecer la telemetría con contexto específico del dominio (por ejemplo, transacciones de negocio, IDs de usuario) que resulta imposible capturar de forma genérica, mientras confían en la configuración predeterminada proporcionada para producir telemetría lista para usar.

---
title: "Figura 2: Modelo de propiedad compartida entre los equipos de plataforma y los responsables de las aplicaciones."
config:
  flowchart:
    curve: basis
---
flowchart TD
    subgraph User["Propiedad de la aplicación"]
        Application["Aplicación"]:::node
        Config["⚙️<br>Config"]:::node
    end

    subgraph Platform["Propiedad de la plataforma"]
        Collector[("🔀️<br>Pipelines<br>del Collector")]:::node
        BaseConfig["⚙️<br>Config base"]:::node
    end

    subgraph Application["Aplicación"]
        AppCode["💼<br>Lógica de negocio"]:::node
        ThirdParty["👽<br>Bibliotecas de terceros"]:::node
        subgraph OTel["OpenTelemetry"]
            InstLibs["📦<br>Instrumentación"]:::node
            OTelSDK["📦<br>OTel SDK"]:::node
            OTelAPI["📦<br>OTel API"]:::node
        end
    end

    Sink[("🗄️ Backend de observabilidad")]:::node

    AppCode L_AppCode_API@-- Usa --> OTelAPI
    ThirdParty L_ThirdParty_API@-- Usa --> OTelAPI
    InstLibs L_InstLibs_API@-- Usa --> OTelAPI
    OTelAPI L_SDK_API@-. Implementado por .-> OTelSDK

    Config L_Config_InstLibs@-.-> InstLibs
    Config L_Config_SDK@-.-> OTelSDK
    OTelSDK L_SDK_Collector@-- Exporta --> Collector
    Collector L_Collector_Sink@--> Sink
    BaseConfig L_BaseConfig_Config@-- Extendido por --> Config

    classDef node fill:#ffffff, stroke:#818cf8, stroke-width:2px, color:#6b7280
    style User fill:#eef2ff, stroke:#818cf8, stroke-width:1px, color:#818cf8
    style Platform fill:#eef2ff, stroke:#818cf8, stroke-width:1px, color:#818cf8
    style Application fill:#eef2ff, stroke:#818cf8, stroke-width:1px, color:#818cf8
    style OTel fill:#dde4ff, stroke:#818cf8, stroke-width:1px, color:#818cf8
    linkStyle 0,1,2 stroke:#7dd3fc, fill:none, stroke-width:3px
    linkStyle 3,4,5,8 stroke:#fde68a, fill:none, stroke-width:3px
    linkStyle 6,7 stroke:#a3e635, fill:none, stroke-width:3px

    L_AppCode_API@{ animation: fast }
    L_ThirdParty_API@{ animation: fast }
    L_InstLibs_API@{ animation: fast }
    L_SDK_API@{ animation: slow }
    L_Config_InstLibs@{ animation: slow }
    L_Config_SDK@{ animation: slow }
    L_SDK_Collector@{ animation: fast }
    L_Collector_Sink@{ animation: fast }
    L_BaseConfig_Config@{ animation: slow }

Este modelo se apoya en el diseño de la API de OpenTelemetry para abstraer los detalles de implementación. Recomendamos considerar el uso directo de las distintas APIs de señal y evitar construir abstracciones adicionales sobre ellas, a menos que aporten más valor que simplemente ocultar los detalles de implementación. Cuando sea necesario, se pueden utilizar características del SDK (por ejemplo, Metric Views o Span Processors) para transformar la telemetría a nivel de aplicación (ver Directriz 4).

En definitiva, los responsables de las aplicaciones deben seguir siendo propietarios de los datos de telemetría emitidos por sus aplicaciones (tanto las instrumentadas manualmente como las instrumentadas automáticamente), y responsables de su calidad y resiliencia. Esto incluye monitorizar y alertar sobre la telemetría del SDK, configurada automáticamente por el equipo de plataforma en los lenguajes que lo permiten, y optimizar su configuración según las necesidades específicas de cada aplicación. Esto implica ajustar componentes del SDK como el BatchSpanProcessor o el PeriodicMetricReader para cambiar el tamaño de los búferes, las colas de reintento, los límites de cardinalidad o los tiempos de espera, según lo requieran sus volúmenes de telemetría.

Al implementar esta directriz, las organizaciones pueden esperar lograr:

  • Correlación con los resultados de negocio: la telemetría emitida por las aplicaciones contiene el contexto de dominio y lógica de negocio necesario para correlacionar la experiencia del usuario con los componentes técnicos y la infraestructura.
  • Propiedad y responsabilidades claras: se garantiza la procedencia de los datos, lo que permite a los equipos medir la calidad de la telemetría y asegurar que los estándares se adopten a escala.
  • Mejor uso de las señales de telemetría: a medida que los responsables de las aplicaciones se familiarizan más con las señales de OpenTelemetry, guiados por los estándares de la organización, mejora el uso óptimo de las APIs de OpenTelemetry.
  • Producción de telemetría fiable: monitorizar las métricas internas del SDK proporciona a los responsables de las aplicaciones o de la plataforma la información necesaria para optimizar aspectos como el encolado, los reintentos o la agrupación (batching) de los datos de telemetría.

3. Mantener un conjunto de Collector Gateways gestionados de forma centralizada

Retos abordados: 2, 3, 4 | Acciones de implementación: 1, 3, 5

Recomendamos que la telemetría en este tipo de entorno de Kubernetes se ingiera automáticamente en una capa centralizada, desplegada como un Collector Gateway de OpenTelemetry. La configuración base proporcionada como parte de la Directriz 1 debe garantizar que la telemetría se exporte a esta capa mediante OTLP.

---
title: "Figura 3: Comportamiento general de un Collector Gateway de OpenTelemetry."
config:
  flowchart:
    curve: basis
---
flowchart LR
    subgraph App["Aplicación"]
        SDK["📦 OTel SDK"]:::node
    end

    LB["⚖️Balanceador de carga"]:::node

    subgraph OTelCol["Collector Gateway"]
        direction TB
        C1["🔀 Collector 1"]:::node
        C2["🔀 Collector 2"]:::node
        C3["🔀 Collector 3"]:::node
    end

    Backend[("🗄️ Backend")]:::node

    SDK L_SDK_LB@-- "OTLP" --> LB

    LB L_LB_C1@--> C1
    LB L_LB_C2@--> C2
    LB L_LB_C3@--> C3

    C1 L_C1_Backend@--> Backend
    C2 L_C2_Backend@--> Backend
    C3 L_C3_Backend@--> Backend

    classDef node fill:#ffffff, stroke:#818cf8, stroke-width:2px, color:#6b7280
    style App fill:#eef2ff, stroke:#818cf8, stroke-width:1px, color:#818cf8
    style OTelCol fill:#eef2ff, stroke:#818cf8, stroke-width:1px, color:#818cf8
    linkStyle 0,1,2,3,4,5,6 stroke:#a3e635, fill:none, stroke-width:3px

    L_SDK_LB@{ animation: fast }
    L_LB_C1@{ animation: fast }
    L_LB_C2@{ animation: fast }
    L_LB_C3@{ animation: fast }
    L_C1_Backend@{ animation: fast }
    L_C2_Backend@{ animation: fast }
    L_C3_Backend@{ animation: fast }

En entornos multiinquilino, puede ser necesario encadenar varios Collector Gateways para adaptarse a distintos escenarios. Por ejemplo, configuraciones multiclúster con Gateways locales por clúster y un Gateway global para el muestreo de cola (tail sampling) (ver Directriz 4), o Gateways delimitados por namespace y gestionados por equipos independientes, que alimentan a un Gateway de todo el clúster en entornos muy federados.

Idealmente, la configuración base del SDK debe seleccionar automáticamente el endpoint de Collector más óptimo y las credenciales necesarias según la información disponible en el entorno de la aplicación (por ejemplo, el enrutamiento de tráfico basado en la localidad, cambiando condicionalmente la dirección del servidor según el nombre del entorno, etc.).

Por último, dependiendo de condiciones específicas de la organización, las distintas señales de OpenTelemetry pueden recibir distintos requisitos no funcionales. Por ejemplo, debido a sus volúmenes de telemetría estables y su uso en alertas críticas, las métricas pueden tener requisitos de fiabilidad más altos que los spans, favoreciendo el descarte de datos en estos últimos antes de afectar a las primeras. Para adaptarse a estas condiciones, los equipos de plataforma pueden considerar distintas opciones, entre ellas:

  • Gateways aislados por señal: desplegar Gateways separados para logs, métricas y spans. Los despliegues aislados simplifican la asignación de recursos de cómputo y la planificación de capacidad por señal, pero la configuración de procesadores compartida debe duplicarse entre los Gateways. Esto puede gestionarse mediante herramientas externas de plantillado, como Kapitan o Kustomize, o usando múltiples ubicaciones de configuración que se sobrescriban entre sí. Sin embargo, puede aumentar el esfuerzo de mantenimiento.
  • Varios memory limiters en un único Gateway: definir configuraciones de memory_limiter separadas por señal, con distintos umbrales. Esto depende de que el receptor OTLP situado delante de un memory_limiter devuelva un código de error reintentable a los clientes OTLP (por ejemplo, SDKs u otros Collectors) cuando se rechaza la telemetría, aplicando contrapresión (backpressure) según sea necesario. Las canalizaciones con menor prioridad pueden configurarse entonces con umbrales de memory limiter más bajos para aplicar la contrapresión antes, dejando margen de memoria para las canalizaciones de mayor prioridad.

Los ingenieros de plataforma deben aprovechar la telemetría interna del Collector para garantizar la fiabilidad de los datos ingeridos, procesados y exportados por sus canalizaciones, y optimizar su configuración en consecuencia. Esto incluye configurar componentes como el memory_limiter, u opciones de OTLP como sending_queue o retry_on_failure. Estas métricas deben usarse para evitar el autoescalado predeterminado basado en CPU de los Collector Gateways, escalando las flotas según la profundidad de la cola de la canalización o el consumo de memoria, para manejar picos repentinos de telemetría.

Al implementar esta directriz, las organizaciones pueden esperar lograr:

  • Canalizaciones optimizadas para los requisitos de los datos de observabilidad: al combinar configuraciones de exportador y receptor OTLP con canalizaciones de Collector fiables y balanceadas, los equipos pueden cumplir sus requisitos de fiabilidad por señal.
  • Uso eficiente de los recursos de cómputo: los Gateways centralizados y escalados horizontalmente utilizan los recursos de cómputo de forma más eficiente que los DaemonSets por nodo o los Sidecars por pod en entornos heterogéneos y multiinquilino. Los DaemonSets normalmente deben sobreaprovisionarse para manejar tamaños de nodo variables (es decir, un solo nodo puede servir a 4 o 40 pods de aplicación) y un volumen de telemetría por pod variable que fluctúa con el tiempo. Mantener una huella pequeña por nodo es importante, ya que los equipos a menudo tienen dificultades para programar cargas de trabajo en nodos más pequeños. Un nivel de Gateway central escala de forma independiente, dimensionado según el volumen total de telemetría.
  • Configuración de Collector consolidada: como se describe en la Acción 3, este modelo permite un despliegue consolidado de la configuración del Collector en múltiples capas, minimizando el esfuerzo de mantenimiento y reduciendo el riesgo de fallos por cambios.

4. Agregar, procesar y muestrear la telemetría de forma eficiente en distintas capas

Retos abordados: 3, 4 | Acciones de implementación: 2, 4

A nivel de aplicación, el diseño de clientes de OpenTelemetry desacopla las APIs de instrumentación de sus implementaciones en el SDK. Esto permite a los autores de la instrumentación (incluidos los responsables de aplicaciones o bibliotecas) usar la API para registrar mediciones, crear spans o emitir registros de log, sin tener que definir cómo se agregarán en memoria, procesarán y finalmente exportarán. Esta decisión puede posponerse hasta el momento en que se crean los proveedores de meter, tracer y logger como parte de la configuración del SDK. La configuración de estos aspectos debe ser compartida, con los equipos de plataforma proporcionando una capa básica de configuración, y los responsables de las aplicaciones extendiendo esa configuración para sus casos de uso particulares.

A nivel de sistema distribuido, se pueden usar distintas técnicas de muestreo de trazas para almacenar de forma eficiente y coherente las trazas más valiosas. Consulta el Apéndice 1 para una introducción a estas técnicas.

Cuando se implementa el muestreo de trazas, el uso coherente de las convenciones semánticas se vuelve fundamental. Las métricas ofrecen vistas completas (aunque agregadas) de la telemetría, usando Exemplars para correlacionarse con spans de traza de alta granularidad para una operación determinada, que a su vez pueden enlazarse con logs y otras señales de telemetría (por ejemplo, perfiles). El uso de convenciones semánticas estándar y atributos de recurso coherentes también potencia la correlación entre estas señales, permitiendo a los operadores «acercarse» desde flujos de métricas agregadas a largo plazo hasta trazas contextuales de alta granularidad.

El siguiente diagrama ofrece un resumen de las distintas capas en las que se puede configurar la agregación, el procesamiento y el muestreo en un escenario multiclúster con muestreo de cola.

---
title: "Figura 4: Arquitectura multiinquilino con balanceo de carga global basado en Trace ID y muestreo de cola."
config:
  flowchart:
    curve: basis
---
flowchart LR
    subgraph LocalA["Gateway local"]
        direction LR
        LA1["🔀 Collector"]:::node ~~~ LA2["🔀 Collector"]:::node
    end
    subgraph ClusterA["Clúster A"]
        direction TB
        AppA["📦 OTel SDK"]:::node
        LocalA
    end

    subgraph LocalB["Gateway local"]
        direction LR
        LB1["🔀 Collector"]:::node ~~~ LB2["🔀 Collector"]:::node
    end

    subgraph ClusterB["Clúster B"]
        direction TB
        AppB["📦 OTel SDK"]:::node
        LocalB
    end

    subgraph LB_Layer["Capa de balanceo de carga"]
        direction TD
        GLB1["🔀 Collector"]:::node ~~~ GLB2["🔀 Collector"]:::node ~~~ GLB3["🔀 Collector"]:::node
    end

    subgraph SamplingLayer["Capa de muestreo de cola"]
        direction TD
        TS1["🔀 Collector"]:::node ~~~ TS2["🔀 Collector"]:::node ~~~ TS3["🔀 Collector"]:::node
    end

    subgraph GlobalTier["Gateway global unificado"]
        direction LR
        LB_Layer
        SamplingLayer
    end

    ObsBackend[("🗄️ Backend de observabilidad")]:::node

    AppA L_AppA_LocalA@-- OTLP --> LocalA
    AppB L_AppB_LocalB@-- OTLP --> LocalB

    LocalA L_LocalA_LBLayer@-- "OTLP (spans)" --> LB_Layer
    LocalB L_LocalB_LBLayer@-- "OTLP (spans)" --> LB_Layer
    LB_Layer L_LBLayer_Sampling@-- "Enrutar por<br>Trace ID" --> SamplingLayer

    LocalA L_LocalA_Backend@-- "OTLP (métricas y logs)" --> ObsBackend
    LocalB L_LocalB_Backend@-- "OTLP (métricas y logs)" --> ObsBackend
    SamplingLayer L_Sampling_Backend@-- "OTLP (spans muestreados)" --> ObsBackend

    AppB -.- n1["Muestreo en cabecera, agregación, límites, etc."]:::note
    LocalA -.- n2["Redacción, enriquecimiento, OTTL, gobernanza, etc."]:::note
    SamplingLayer -.- n4["Muestreo de trazas, post-procesamiento"]:::note

    classDef node fill:#ffffff, stroke:#818cf8, stroke-width:2px, color:#6b7280
    classDef note fill:#f9fafb, stroke:#c7d2fe, stroke-width:1px, color:#9ca3af
    style ClusterA fill:#eef2ff, stroke:#818cf8, stroke-width:1px, color:#818cf8
    style ClusterB fill:#eef2ff, stroke:#818cf8, stroke-width:1px, color:#818cf8
    style LocalA fill:#dde4ff, stroke:#818cf8, stroke-width:1px, color:#818cf8
    style LocalB fill:#dde4ff, stroke:#818cf8, stroke-width:1px, color:#818cf8
    style GlobalTier fill:#eef2ff, stroke:#818cf8, stroke-width:1px, color:#818cf8
    style LB_Layer fill:#dde4ff, stroke:#818cf8, stroke-width:1px, color:#818cf8
    style SamplingLayer fill:#dde4ff, stroke:#818cf8, stroke-width:1px, color:#818cf8
    linkStyle 6,7 stroke:#7dd3fc, fill:none, stroke-width:3px
    linkStyle 8,9,10,13 stroke:#a3e635, fill:none, stroke-width:3px
    linkStyle 11,12 stroke:#fde68a, fill:none, stroke-width:3px
    linkStyle 14,15,16 stroke:#c7d2fe, fill:none, stroke-width:1px

    L_AppA_LocalA@{ animation: fast }
    L_AppB_LocalB@{ animation: fast }
    L_LocalA_LBLayer@{ animation: fast }
    L_LocalB_LBLayer@{ animation: fast }
    L_LBLayer_Sampling@{ animation: fast }
    L_LocalA_Backend@{ animation: fast }
    L_LocalB_Backend@{ animation: fast }
    L_Sampling_Backend@{ animation: fast }

Por lo general, el procesamiento de la telemetría debe realizarse lo más cerca posible de la capa de aplicación, evitando costos de cómputo y transferencia. Sin embargo, posponer las decisiones de procesamiento a distintas capas del Collector puede ser deseable en ciertas situaciones, como facilitar el mantenimiento, aplicar estándares, realizar filtrados o transformaciones avanzadas con OTTL, o asegurar las canalizaciones con reglas de redacción para garantizar que la información sensible nunca llegue a un backend determinado.

Al combinar el muestreo inteligente, la agregación de métricas en distintas capas y procesadores centrales de transformación/filtrado para reducir la telemetría ruidosa, esta arquitectura puede reducir los costos de transferencia y cómputo, preservando a la vez la visibilidad operativa para los equipos de ingeniería.

Al implementar esta directriz, las organizaciones pueden esperar lograr:

  • Volúmenes de telemetría eficientes: el uso óptimo de las señales de OpenTelemetry, el muestreo y la agregación proporcionan volúmenes de telemetría que permiten a las organizaciones equilibrar entre la alta granularidad, el costo y los requisitos de observabilidad.
  • Uso eficiente de los recursos de cómputo: ubicar el procesamiento de datos en distintos niveles limita la transferencia de datos y los recursos de cómputo asociados a datos que pueden agregarse o filtrarse en etapas tempranas.
  • Gobernanza central y guardrails: los equipos de plataforma cuentan con un punto central para controlar la emisión de datos, lo que les permite filtrar, transformar, redactar o bloquear por completo la telemetría que no siga los estándares de la organización o no respete los límites de volumen de datos, protegiendo a la organización de enviar datos no deseados a los backends.

Implementación

1. Usar el OpenTelemetry Operator, o paquetes internos compartidos, para la configuración a nivel de aplicación

Directrices implementadas: 1

Si el entorno en cuestión se encuentra dentro de las versiones de Kubernetes y los lenguajes instrumentados soportados, recomendamos priorizar el uso del OpenTelemetry Operator para Kubernetes para la auto-instrumentación. Esto implica:

  • Instalar el OpenTelemetry Operator.
  • Crear los CRs de Instrumentation correspondientes para configurar los SDKs y la instrumentación.
  • Añadir anotaciones a pods individuales o a namespaces (para instrumentar todos los pods de un namespace).

Si desplegar el OpenTelemetry Operator no es posible o compatible, recomendamos proporcionar a los responsables de las aplicaciones recursos en tiempo de build para configurar fácilmente el SDK de OpenTelemetry y las bibliotecas de instrumentación. Esto puede implementarse siguiendo dos modelos principales:

  • Para los lenguajes soportados por la instrumentación sin código, recomendamos proporcionar imágenes de contenedor base para descargar agentes/bibliotecas de instrumentación, ofrecer una configuración predeterminada y configurar el CMD base en la imagen de contenedor resultante para utilizar estos ajustes.
  • Para los lenguajes no soportados por la instrumentación sin código, recomendamos proporcionar bibliotecas específicas de lenguaje compartidas que se encarguen de configurar el SDK de OpenTelemetry y las bibliotecas de instrumentación de forma programática, ofreciendo hooks para que los usuarios de dichas bibliotecas extiendan esta configuración según sea necesario.

Este modelo sin Operator pone a los responsables de las aplicaciones a cargo de usar estas imágenes de contenedor base o bibliotecas compartidas en su código. Aunque inicialmente puede requerir más esfuerzo que la instrumentación adjuntada automáticamente, proporciona un mecanismo para que los equipos de plataforma gestionen actualizaciones escalonadas o cambios de configuración mediante incrementos de versión menores de sus bibliotecas internas, sin requerir más cambios de código por parte de los responsables de las aplicaciones.

Al gestionar la configuración centralizada en imágenes de contenedor base o bibliotecas internas, y cuando el lenguaje lo permita, recomendamos estandarizar el uso de la configuración declarativa. Aunque actualmente no está totalmente soportada por todos los lenguajes, este modelo de configuración basado en YAML aporta coherencia a la configuración del SDK y de la instrumentación.

2. Incluir los estándares de la organización en la configuración predeterminada y extensible a nivel de aplicación

Directrices implementadas: 1, 2, 4

Independientemente de cómo se entregue la configuración como parte de la Acción 1, recomendamos que el equipo de plataforma incluya la siguiente configuración base mínima como parte de su oferta:

  • Exportadores: OTLP HTTP/protobuf (predeterminado) u OTLP gRPC configurado para exportar al Collector más óptimo (por ejemplo, un Gateway local en el mismo clúster). Consulta el Apéndice 2 y la Acción 3 para más detalles sobre los efectos secundarios de usar OTLP gRPC con Services estándar de Kubernetes.

    • Nota: los endpoints de backend/SaaS o las claves de API no deben incluirse en la configuración a nivel de aplicación, ya que recomendamos gestionarlos en un Collector Gateway.
  • Propagadores: W3C Trace Context (tracecontext) para garantizar que las trazas distribuidas no se rompan en los límites entre servicios. Si es necesario, incluye formatos heredados como opciones secundarias (la API de Propagators priorizará en el orden en que se configuren).

  • Detectores de recurso: auto-detectores para la infraestructura subyacente (por ejemplo, proveedor de nube, Kubernetes, SO, contenedor) para lograr coherencia sin intervención manual.

  • Bibliotecas de instrumentación: asegúrate de que un conjunto mínimo de bibliotecas de instrumentación esté configurado de forma predeterminada. Si se usa la auto-instrumentación, los equipos de plataforma no deben habilitar todas las bibliotecas de instrumentación por defecto, sino seleccionar cuidadosamente las más críticas para su entorno, priorizando la instrumentación de cliente y servidor (por ejemplo, gRPC, HTTP, mensajería, base de datos).

  • Procesadores, readers y views: ajustes específicos del backend en uso (por ejemplo, temporalidad de agregación, intervalos de exportación, límites de atributos) o estándares de toda la organización (por ejemplo, atributos de span/métrica).

    • Nota: dependiendo de la implementación de cada lenguaje, los exportadores OTLP pueden reintentar al recibir errores reintentables como HTTP 429, 503, o gRPC UNAVAILABLE con RetryInfo opcional. Sin embargo, estos exportadores no tienen las mismas capacidades que los Collectors en términos de colas de envío, y descartarán lotes de datos si no tienen éxito. Los equipos de plataforma deben gestionar valores predeterminados razonables para el tamaño de estos búferes y priorizar la exportación a Collectors locales (por ejemplo, un Gateway local al clúster) para sacar la telemetría del proceso de la aplicación de la forma más rápida y fiable posible. Los responsables de las aplicaciones deben monitorizar la telemetría del SDK, cuando esté disponible, y reaccionar en consecuencia.
  • Atributos de recurso específicos de la organización: convenciones estándar críticas para el enrutamiento, la facturación y la propiedad. Como mínimo, recomendamos:

    • service.name, idealmente extraído de variables de entorno existentes o de labels inyectados mediante herramientas de CI/CD.
    • service.version para identificar el origen de la telemetría durante despliegues blue/green o rollouts progresivos.
    • service.namespace o service.owner para la propiedad del recurso.
    • deployment.environment.name (por ejemplo, production, staging).
    • Otros atributos inyectados como variables de entorno mediante la Downward API de Kubernetes (es decir, valueFrom.fieldRef.fieldPath), estandarizados en todas las plantillas de despliegue de aplicaciones.

Los equipos de plataforma deben proporcionar formas para que los responsables de las aplicaciones sobrescriban y extiendan esta configuración predeterminada. El mecanismo para hacerlo dependerá de los métodos establecidos en la Acción 1 para proporcionar la configuración de OTel. Las posibles opciones se documentan en el Apéndice 3

3. Usar el OpenTelemetry Operator o Helm Charts para desplegar Collector Gateways

Directrices implementadas: 3

Para desplegar niveles de Gateway centralizados, los equipos de plataforma deben estandarizar en el OpenTelemetry Operator o en los OpenTelemetry Helm Charts oficiales. Ambos soportan flujos de trabajo GitOps, pero requieren consideraciones arquitectónicas específicas para cargas de trabajo empresariales:

  • OpenTelemetry Operator: ideal si el Operator ya se usa para la auto-instrumentación de aplicaciones (Acción 1). El Gateway puede desplegarse creando un CR de OpenTelemetryCollector y estableciendo mode: deployment o mode: statefulset (según los requisitos). El Operator abstrae gran parte del boilerplate de Kubernetes. Consulta la documentación del Operator para más orientación sobre cómo habilitar el autoescalado.
  • Helm Charts oficiales: una mejor opción si los equipos de infraestructura prefieren un control granular sobre los manifiestos nativos de Kubernetes (por ejemplo, configuraciones específicas de Ingress, PodDisruptionBudgets, o reglas de afinidad complejas) sin depender de CRDs.

Independientemente de la herramienta de despliegue elegida, el nivel de Gateway es un punto crítico, y sus responsables deben garantizar que la resiliencia se configure desde el inicio:

  • Configurar memory_limiter: al configurarse como el primer procesador en cada canalización del Collector, esto previene fallos por falta de memoria (OOM) durante picos masivos de telemetría, obligando al Collector a descartar datos y/o aplicar contrapresión cuando el uso de memoria alcanza un umbral configurado. Como se menciona en la Directriz 3, pueden ser necesarios distintos procesadores memory_limiter por señal.
  • Configurar el exportador otlp o otlp_http: asegúrate de que las colas y los reintentos estén alineados con las expectativas de fiabilidad frente al consumo de recursos, manejando fallos transitorios del backend antes de descartar datos. En particular, considera opciones de sending_queue como batch, que permite una transferencia de red eficiente y la propagación de contrapresión, y block_on_overflow, que controla si el Collector debe descartar datos o esperar hasta que haya espacio disponible cuando la cola (persistente o en memoria) esté llena.
  • Considerar la extensión file_storage: si el descarte de datos durante interrupciones prolongadas del servicio del backend de observabilidad es crítico para el funcionamiento del negocio, considera configurar sending_queue.storage en tu exportador OTLP con la extensión file_storage. Con esta extensión configurada, si el backend no está disponible o limita la tasa de exportaciones, el Collector almacenará los datos en disco de forma temporal y reintentará automáticamente, evitando la pérdida de datos. Consulta el Apéndice 4 para conocer notas sobre el despliegue de la extensión file_storage.
  • Balanceo de carga de gRPC: OTLP/gRPC puede ser muy eficiente, pero el enrutamiento estándar de Services de Kubernetes puede hacerlo ineficiente. Consulta el Apéndice 2 para implementar el balanceo de carga de gRPC, o considera OTLP/HTTP (el predeterminado para la mayoría de los SDKs).
  • Escalar según la memoria y la telemetría interna: utiliza el Horizontal Pod Autoscaler (HPA) de Kubernetes combinado con métricas personalizadas (ver Acción 5). Configura el clúster para escalar las réplicas del Gateway según el uso de memoria, las conexiones activas o la profundidad de la cola de la canalización.
  • Configuración como código: almacena los values de Helm o los CRs del Operator en un repositorio Git central y usa herramientas como ArgoCD o Flux para desplegarlos. Esto proporciona un registro de auditoría y permite despliegues escalonados y reversiones instantáneas.

4. Configurar los procesadores del Collector para volúmenes de telemetría eficientes

Directrices implementadas: 4

Para enriquecer la telemetría con contexto de infraestructura, reducir los costos de transferencia e ingesta de datos de telemetría de bajo valor, y aplicar el cumplimiento normativo antes de que los datos salgan de la red corporativa, el equipo de plataforma debe considerar configurar las canalizaciones en los Collector Gateways para ejecutar los siguientes pasos de procesamiento (en orden):

  • Procesador k8s_attributes: aunque algunos detalles de recursos de Kubernetes (como el ID del pod o el nombre del namespace) pueden añadirse a nivel de aplicación (ver Acción 2), el equipo de plataforma debe garantizar un cumplimiento del 100 % para las cargas de trabajo no gestionadas. Esto incluye campos no disponibles a través de la Downward API. Configura este procesador para extraer y añadir atributos como k8s.deployment.name, k8s.statefulset.name, etc., según la IP del pod de la conexión entrante. Consulta el Apéndice 5 para conocer detalles a tener en cuenta al usar el procesador k8s_attributes.
  • Procesadores para filtrar y transformar datos: como medida de respaldo para aplicaciones que no pudieron aplicar estos ajustes a nivel de SDK antes de enviarlos al Collector, usa procesadores como attributes, filter, redaction, resource, o transform para definir reglas que:
    • Descarten trazas de un solo span y logs de acceso para endpoints rutinarios (/health, /metrics, /ready) o logs de depuración no accionables (level=DEBUG o level=TRACE).
    • Eliminen atributos ruidosos específicos (por ejemplo, process.command_line) que pueden ser menos útiles en entornos de Kubernetes donde estos atributos están presentes en las canalizaciones de CI/CD.
    • Cualquier otro procesamiento para eliminar telemetría ruidosa y de bajo valor.
  • Procesador tail_sampling: define políticas de retención estrictas, por ejemplo, conservando el 100 % de las trazas que contienen errores o superan un umbral de latencia, y una pequeña base (por ejemplo, el 5 %) de solicitudes exitosas y de duración normal. Como se documenta en la Directriz 4, esto requiere dos capas de collectors, usando el exportador load_balancing en la primera capa para enrutar las trazas a la segunda capa según el Trace ID. Consulta más información sobre la exportación con balanceo de carga en nuestra documentación.

Esta no es una lista exhaustiva, y los Collectors de OpenTelemetry cuentan con muchos procesadores y connectors que permiten a las organizaciones extraer más valor de sus datos de telemetría.

5. Monitorizar SDKs y Collectors para garantizar los requisitos de fiabilidad

Directrices implementadas: 2, 3

Los SDKs y Collectors de OpenTelemetry exportan telemetría estándar que describe el estado interno de sus componentes en funcionamiento. Los responsables de las aplicaciones y los equipos de plataforma deben garantizar que esta telemetría se produzca de forma fiable, se monitorice y se actúe sobre ella según sea necesario.

Para identificar y monitorizar la pérdida de datos que ocurre incluso antes de que la telemetría salga del proceso de la aplicación (por ejemplo, si la cola interna del SDK se llena), recomendamos:

  • Cuando el ecosistema del lenguaje lo soporte (por ejemplo, Java mediante la biblioteca de instrumentación opentelemetry-sdk, o Go mediante el paquete sdk/metric), habilita las métricas propias del SDK (self-metrics) para exponer las capacidades internas de la cola, los spans descartados y la latencia del exportador. Las convenciones semánticas del SDK de OpenTelemetry definen la telemetría que deben producir los SDKs, pero el soporte varía según el lenguaje.
  • Los lenguajes que carecen de soporte nativo de métricas del SDK para la telemetría interna pueden seguir soportando diagnósticos internos de otras formas (por ejemplo, EventSource de .NET, java.util.logging de Java, o diag de Node.js). Los usuarios deben consultar las implementaciones específicas para configurarlas según sus necesidades particulares y nivel de detalle.

Para monitorizar la salud de los niveles de agregación y procesamiento, el equipo de plataforma debe capturar activamente la telemetría interna del Collector y generar alertas sobre ella. Recomendamos seguir estos pasos:

  • Exportar la telemetría interna mediante OTLP: configura el bloque service.telemetry para emitir métricas internas mediante OTLP al backend de observabilidad, siguiendo los estándares de toda la empresa. Además de para la monitorización, estas métricas también deben usarse como fuente de datos para las decisiones de autoescalado (ver Acción 3). Ten en cuenta que esta configuración de OTLP es independiente del exportador OTLP configurado en las canalizaciones del Collector.
  • Monitorizar y solucionar problemas: sigue las recomendaciones presentes en las secciones de monitorización y solución de problemas de la documentación del Collector, y crea las alertas de alta prioridad necesarias para detectar el agotamiento de recursos y los fallos de recepción/exportación antes de que los datos se descarten en réplicas individuales.

Implementaciones de referencia

Apéndice

1. Técnicas de muestreo de trazas distribuidas

A un nivel muy general, el muestreo puede configurarse principalmente en dos capas distintas:

  • SDK: el muestreo en cabecera (head sampling) configurado a nivel de SDK proporciona un uso eficiente de los recursos de cómputo, ya que las trazas no muestreadas nunca se registran ni se exportan desde una aplicación determinada. Sin embargo, las decisiones de muestreo deben tomarse en el momento de crear el span, lo que normalmente resulta en un muestreo probabilístico que podría pasar por alto trazas críticas (por ejemplo, las que contienen errores).
  • Collector: los Collectors habilitan dos técnicas de muestreo principales:
    • Muestreo probabilístico: se puede configurar en cualquier capa del Collector y no requiere coordinación entre Collectors, siempre que se use el mismo algoritmo y semilla para una misma traza.
    • Muestreo de cola (tail sampling): una única réplica del Collector debe almacenar en memoria todos los spans de una traza determinada antes de tomar una decisión. Dado que el despliegue de una sola réplica no se recomienda en entornos de producción, este modelo normalmente requiere una capa de Collectors para balancear la carga de los spans según el Trace ID, y otra capa para realizar el muestreo.

El muestreo de cola requiere más recursos para operar y mantener. Sin embargo, ofrece una forma más rica de definir políticas de muestreo que permiten a las organizaciones almacenar de forma eficiente solo las trazas críticas para la operación de sus servicios. Por ejemplo, trazas con duraciones superiores a un umbral determinado, o aquellas que contienen errores en cualquier span de una traza dada.

2. Balanceo de carga de gRPC

gRPC se apoya en HTTP/2, multiplexando muchas solicitudes sobre una única conexión TCP de larga duración. Los Services estándar de Kubernetes operan en la Capa 4 (TCP) usando kube-proxy, por lo que balancean conexiones, no solicitudes individuales. Cuando un SDK, un Collector local o una aplicación se conecta a un Gateway a través de un Service estándar de Kubernetes, establece una conexión TCP y la mantiene abierta indefinidamente. Como resultado, el 100 % de la telemetría de ese agente fluirá hacia un único pod del Gateway.

En entornos de alto rendimiento, esto crea puntos calientes (hot spots) en réplicas específicas del Gateway, ya que los pods recién escalados no reciben tráfico, lo que socava el autoescalado horizontal de pods y arriesga el agotamiento de recursos en los pods de larga duración.

Para distribuir la telemetría de forma equitativa, los equipos de plataforma deben considerar uno de los siguientes tres patrones:

Balanceo de carga en el lado del cliente

Los exportadores OTLP gRPC pueden realizar el balanceo de carga en el lado del cliente, consultando el DNS de Kubernetes para descubrir las IPs de todos los pods de Gateway disponibles y distribuyendo las solicitudes entre ellos en modo round-robin.

Para lograr esto, el nivel de Gateway debe desplegarse con un Headless Service, de modo que las consultas DNS devuelvan una lista de IPs de pods en lugar de una única IP virtual.

  • OpenTelemetry Operator: si despliegas un CR de OpenTelemetryCollector en modo statefulset, el Operator genera automáticamente un servicio headless llamado {collector-name}-collector-headless.{namespace}.svc.cluster.local. Si se despliega como deployment, tendrás que crear manualmente un Service headless de Kubernetes con ClusterIP: None.
  • Helm Chart: establece service.clusterIP: None al desplegar el Gateway.

El exportador OTLP emisor debe configurarse para usar el resolvedor de DNS y el balanceador round-robin. Al configurar el exportador OTLP en el Collector (por ejemplo, desde un Collector local hacia un Gateway):

  • endpoint debe comenzar con dns:/// para indicar al cliente gRPC que realice una resolución de DNS continua.
  • balancer_name debe establecerse en round_robin (predeterminado en el Collector desde la versión v0.105.0).

Los distintos SDKs cliente pueden configurar los clientes gRPC de formas diferentes. Consulta las implementaciones específicas de cada cliente para configurar el balanceo de carga de gRPC en el lado del cliente.

Proxy de capa 7 / Service Mesh

En este enfoque, se coloca un proxy de Capa 7 compatible con HTTP/2 entre el exportador OTLP gRPC y el nivel de Gateway. Dado que el proxy opera en la Capa 7, comprende los frames de HTTP/2. Acepta la única conexión TCP de larga duración, inspecciona las solicitudes gRPC individuales y las distribuye de forma equitativa entre todos los pods de Gateway del backend.

Métodos de implementación:

  • Service Mesh (por ejemplo, Istio, Linkerd): si el clúster ya ejecuta un service mesh, el balanceo de carga de gRPC se gestiona automáticamente. El sidecar del mesh (o equivalente) intercepta el tráfico de salida del agente perimetral y lo balancea entre los pods del Gateway.
  • Proxy independiente (por ejemplo, Envoy, NGINX): despliega un proxy Envoy o NGINX (configurado para grpc_pass) directamente delante del nivel de Gateway. Los agentes perimetrales apuntan al Service de Kubernetes del proxy, y el proxy balancea el tráfico hacia los Gateways.
  • Ingress Controllers: si los SDKs o Collectors locales envían telemetría desde fuera del clúster (o entre clústeres), asegúrate de que el Ingress Controller (por ejemplo, NGINX Ingress, Traefik, AWS ALB) esté configurado explícitamente para soportar gRPC y el enrutamiento de backend con HTTP/2.

Reciclaje de conexiones en el lado del servidor

Por último, el receptor OTLP gRPC del Gateway puede configurarse para cerrar las conexiones de larga duración después de un tiempo determinado usando keepalive.server_parameters.max_connection_age. Cuando una conexión alcanza esa antigüedad, el servidor envía un frame GoAway, obligando al cliente a reconectarse. Al reconectarse, el enrutamiento estándar de Service de Kubernetes redistribuye al cliente entre los pods de Gateway disponibles.

Esta opción no requiere ningún cambio en el lado del cliente: solo es necesario actualizar la configuración del receptor del Gateway:

receivers:
  otlp:
    protocols:
      grpc:
        keepalive:
          server_parameters:
            max_connection_age: 60s
            max_connection_age_grace: 10s

Este enfoque es menos preciso que el balanceo por solicitud (el tráfico solo se redistribuye al reconectarse, no por solicitud), y los pods recién escalados no recibirán tráfico hasta que expiren las conexiones existentes. Sin embargo, es la opción más simple, ya que no requiere Services headless, resolvedores de DNS ni proxies de Capa 7.

Recomendación

Si la organización ya ejecuta un Service Mesh, la opción de proxy de Capa 7 no requiere ninguna configuración adicional del lado de OpenTelemetry. Si no hay un Service Mesh y el tráfico permanece dentro del mismo clúster, el balanceo de carga en el lado del cliente ofrece la distribución más precisa. El reciclaje de conexiones en el lado del servidor es el punto de partida más simple cuando ninguna de las dos opciones anteriores está disponible. Alternativamente, incluyendo los casos en los que los operadores no tienen control sobre el backend receptor (por ejemplo, conexiones enrutadas a través de internet público), considera usar OTLP/HTTP (ver Acción 2), que opera sobre HTTP/1.1 o conexiones HTTP/2 de corta duración y no sufre el mismo comportamiento de fijación (pinning).

3. Sobrescrituras de configuración del SDK

Dependiendo de los métodos establecidos en la Acción 1 para proporcionar la configuración de OTel, el equipo de plataforma debe documentar exactamente cómo los desarrolladores heredan la base y cómo pueden extenderla:

  • OpenTelemetry Operator: el equipo de plataforma aprovisiona un CR central de Instrumentation en el clúster. Los responsables de las aplicaciones pueden habilitarlo o deshabilitarlo mediante anotaciones a nivel de pod o namespace.
    • Sobrescrituras básicas: los responsables de las aplicaciones pueden sobrescribir propiedades específicas de la base inyectando variables de entorno estándar directamente en el spec de su Pod. La matriz de compatibilidad detalla el soporte para las distintas variables de entorno según el lenguaje. Además, algunas implementaciones de lenguaje (por ejemplo, Java) permiten configurar las bibliotecas de instrumentación mediante variables de entorno específicas de la biblioteca.
    • Sobrescrituras complejas: si los equipos necesitan modificar el propio CR de Instrumentation (por ejemplo, para añadir samplers personalizados o bibliotecas de auto-instrumentación específicas), el equipo de plataforma debe gestionar el CR mediante Helm o Kustomize. Esto permite a la plataforma mantener una plantilla base mientras los responsables de las aplicaciones proporcionan sobrescrituras locales o archivos de values que se fusionan antes del despliegue en el clúster.
  • Imágenes de contenedor base: de forma similar a lo anterior, los equipos pueden sobrescribir aspectos específicos mediante variables de entorno que sobrescriben los valores predeterminados establecidos en la imagen base.
  • Bibliotecas internas: las bibliotecas internas compartidas deben proporcionar los hooks necesarios para que los usuarios puedan pasar bloques de configuración estándar según se requiera. Por ejemplo, en JavaScript, una biblioteca wrapper para configurar un Node SDK debe permitir al usuario proporcionar configuraciones estándar de NodeSDKConfiguration como resource o traceExporter.
  • Configuración declarativa: los equipos de plataforma pueden aprovechar las funciones de interpolación de variables de entorno de la configuración basada en archivos y permitir que los responsables de las aplicaciones establezcan variables de entorno locales que el archivo YAML base lea, o bien, a medida que madure el estándar de configuración basada en archivos, usar la fusión de configuraciones para combinar un custom-otel.yaml proporcionado por el desarrollador con el base-otel.yaml de la plataforma.

4. Notas de despliegue sobre la extensión file_storage

Si bien el uso de la extensión file_storage y sending_queue.storage del exportador OTLP proporciona garantías adicionales de completitud, esto aleja al despliegue de un modelo stateless, requiriendo que el Gateway se despliegue como un StatefulSet con PersistentVolumeClaims. Al igual que con los ajustes del exportador OTLP, los operadores deben considerar el equilibrio entre la criticidad de descartar datos (en este caso, potencialmente datos obsoletos) y el costo del esfuerzo de mantenimiento y soporte (por ejemplo, gestionar la presión de disco, el redimensionamiento de volúmenes, etc.).

Además, habilitar colas persistentes retrasa la propagación de la contrapresión hacia los clientes downstream. Los datos se almacenan en búfer en disco antes de que se acumule presión de memoria, lo que significa que el memory_limiter no activará la contrapresión de forma temprana. Una vez que la cola persistente se llena, la canalización se bloquea y el receptor devolverá errores reintentables (por ejemplo, 429) a los clientes, señalando la contrapresión.

Los operadores deben dimensionar la cola persistente y monitorizar el uso de disco en consecuencia.

5. Notas de despliegue sobre el procesador k8s_attributes

Si se coloca un proxy entre el pod que emite la telemetría y el Collector que la procesa, asegúrate de que el modo pass-through esté habilitado en el proxy, de modo que el Gateway vea la IP de Pod original de la aplicación, y no la IP del proxy. Alternativamente, inyecta campos disponibles mediante la Downward API (por ejemplo, k8s.pod.uid) como atributos de recurso al configurar los SDKs de OTel, y configura las reglas de asociación de pods de k8s_attributes para que coincidan los atributos de recurso entrantes con un Pod determinado.

Al usar el procesador k8s_attributes, la ServiceAccount utilizada por el Collector debe tener concedidos los permisos RBAC get, watch y list sobre los recursos de Kubernetes correspondientes a los atributos que se extraen, por ejemplo, deployments para k8s.deployment.name y k8s.deployment.uid. La falta de cualquiera de estos permisos hará que el Collector omita silenciosamente el enriquecimiento de los atributos afectados.

Por último, ejecutar este procesador en un Gateway provocará un mayor uso de memoria en cada uno de los Collectors, que escala según el tamaño del clúster. El procesador k8s_attributes mantiene en memoria metadatos relacionados con los objetos del clúster, y cuantos más objetos haya que almacenar en caché, más memoria consumirá el collector.

Cuando se ejecuta como un Gateway, cada pod del Deployment o StatefulSet del collector debe recordar TODOS los metadatos de todo el clúster (a diferencia de ejecutarse como un DaemonSet, donde el pod solo necesita conocer los metadatos de su propio nodo). La documentación del componente contiene más detalles sobre las consideraciones de despliegue y escalado.