Skip to main content

Grafana Agent y OpenTelemetry Operator

Es interesante solo leer sobre esto después de dominar OpenTelemetry.

En Kubernetes tenemos el OpenTelemetry Operator que consigue inyectar automáticamente una instrumentación en la aplicación usando un init container y levanta un collector ya preconfigurado como un sidecar igual que Istio.

Para configurar el collector tenemos custom resources específicos de OpenTelemetry. Es una propuesta muy interesante.

Sin embargo, si decimos que Grafana Agent puede funcionar como collector, ¿deberíamos tener el sidecar? Podemos y no podemos, pero Grafana Agent no tiene la parte que inyecta automáticamente la instrumentación.

OpenTelemetry Operator y Grafana Agent sirven propósitos diferentes, aunque haya algunas superposiciones:

OpenTelemetry Operator:

  • Hace la instrumentación automática de las aplicaciones
  • Configura sidecars automáticamente
  • Gestiona el ciclo de vida de la instrumentación
  • Facilita la configuración vía CRDs (Custom Resources)

Grafana Agent:

  • Enfoque en recolectar y enviar datos a Grafana Cloud
  • Puede recibir datos OTLP, pero no hace instrumentación
  • No tiene capacidad de inyectar instrumentación

Entonces, incluso usando Grafana Agent, aún podrías querer el OpenTelemetry Operator para:

  • Instrumentación automática de las aplicaciones
  • Gestión vía Kubernetes nativo (CRDs)
  • Configuración consistente entre aplicaciones

Una arquitectura posible sería:

App + Auto-instrumentación (vía Operator) --→ Grafana Agent --→ Grafana Cloud

El Operator cuida de la instrumentación, mientras que el Agent cuida del envío a Grafana Cloud.

Por ejemplo, configuraríamos aquí nuestro Grafana Agent para recibir todos los tipos de datos.

apiVersion: monitoring.grafana.com/v1alpha1
kind: GrafanaAgent
metadata:
name: grafana-agent
spec:
flow:
# Receptor OTLP para traces y logs
otelcol.receiver.otlp "default" {
grpc {
endpoint = "0.0.0.0:4317"
}
http {
endpoint = "0.0.0.0:4318"
}
}

# Configuración para Tempo (traces)
otelcol.exporter.otlp "tempo" {
client {
endpoint = "tempo-prod-XX.grafana.net:443"
auth {
basic {
username = "your-username"
password = "your-api-key"
}
}
}
}

# Configuración para Loki (logs)
loki.write "default" {
endpoint {
url = "https://logs-prod-XX.grafana.net/loki/api/v1/push"
basic_auth {
username = "your-username"
password = "your-api-key"
}
}
}

# Service Discovery Kubernetes
discovery.kubernetes "pods" {
role = "pod"
}

# Configuración para Prometheus (métricas)
prometheus.remote.write "default" {
endpoint {
url = "https://prometheus-prod-XX.grafana.net/api/prom/push"
basic_auth {
username = "your-username"
password = "your-api-key"
}
}
}

prometheus.scrape "default" {
targets = discovery.kubernetes.pods.targets
forward_to = [prometheus.remote.write.default.receiver]
clustering {
enabled = true
}
}

Entonces podríamos simplemente configurar un instrumentador del operator así:

apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
name: app-instrumentation
spec:
exporter:
endpoint: http://grafana-agent:4317 # Para traces y logs
metrics:
enable: true
prometheusExporter:
port: 8080 # Puerto que expone /metrics
propagators:
- tracecontext
- baggage
sampler:
type: parentbased_traceidratio
argument: "1"
Aplicación (instrumentada por el Operator)
├──→ /metrics endpoint --→ Grafana Agent scrape --→ Prometheus Cloud
├──→ traces OTLP --------→ Grafana Agent --------→ Tempo Cloud
└──→ logs OTLP ----------→ Grafana Agent --------→ Loki Cloud

Configuramos el grafana agent para hacer scrape de todas las aplicaciones del cluster.

Nada impide no querer usar de esta manera y colocar un collector también y configurar para enviar los datos a tu grafana. El operator tiene un custom resource solo para configuración del collector como sidecar, pero sabiendo que el grafana agent también funciona podemos disminuir muchos contenedores extras en los pods.

Esto solo tiene sentido si estás usando Grafana, si tu stack es otro no te preocupes con esto.