Skip to main content

Grafana Agent e OpenTelemetry Operator

É interessante somente ler sobre isso depois que dominar o OpenTelemetry.

No kubernetes temos o Opetelemetry Operator que consegue injeta automaticamente uma instrumentação na aplicação usando um init container e sobe um collector já pré configurado como um sidecar igual o Istio.

Para configurar o collector temos custom resources específicos do opentelemetry. É uma proposta bem interesante.

Porém se falamos que o grafana agent pode funcionar como collector devíamos ter o sidecar? Podemos e não podemos, mas o grafana agent não tem a parte que injectar automaticamente a instrumentação.

O OpenTelemetry Operator e o Grafana Agent servem propósitos diferentes, mesmo que haja algumas sobreposições:

OpenTelemetry Operator:

  • Faz a instrumentação automática das aplicações
  • Configura sidecars automaticamente
  • Gerencia o ciclo de vida da instrumentação
  • Facilita a configuração via CRDs (Custom Resources)

Grafana Agent:

  • Foco em coletar e enviar dados para Grafana Cloud
  • Pode receber dados OTLP, mas não faz instrumentação
  • Não tem capacidade de injetar instrumentação

Então, mesmo usando Grafana Agent, você ainda pode querer o OpenTelemetry Operator para:

  • Instrumentação automática das aplicações
  • Gerenciamento via Kubernetes native (CRDs)
  • Configuração consistente entre aplicações

Uma arquitetura possível seria:

App + Auto-instrumentação (via Operator) --→ Grafana Agent --→ Grafana Cloud

O Operator cuida da instrumentação, enquanto o Agent cuida do envio para Grafana Cloud.

Por exemplo iriamos configurar aqui o nosso grafana agent para receber todos os tipos de dados.

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

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

# Configuração 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"
}

# Configuração 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
}
}

Então poderíamos simplemente configurar uma instrumentador do operator assim:

apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
name: app-instrumentation
spec:
exporter:
endpoint: http://grafana-agent:4317 # Para traces e logs
metrics:
enable: true
prometheusExporter:
port: 8080 # Porta que expõe /metrics
propagators:
- tracecontext
- baggage
sampler:
type: parentbased_traceidratio
argument: "1"
Aplicação (instrumentada pelo Operator)
├──→ /metrics endpoint --→ Grafana Agent scrape --→ Prometheus Cloud
├──→ traces OTLP --------→ Grafana Agent --------→ Tempo Cloud
└──→ logs OTLP ----------→ Grafana Agent --------→ Loki Cloud

Configuramos o grafana agent para fazer o scrape de todas as aplicações do cluster.

Nada impede de não querer usar dessa maneira e colocar um collector também e configurar para enviar os dados para o seu grafana. O operator tem um custom resource só para configuração do collector como sidecar, mas sabendo que o grafana agent também funciona podemos diminuir muitos containers extras nos pods.

Isso só faz sentido se você estiver usando o Grafana, se sua stack for outra não se preocupe com isso.