Voltar para o blog

OpenTelemetry eBPF Instrumentation: primeiros passos no Linux

Uma API apresenta lentidão, mas os dashboards mostram apenas CPU, memória e disponibilidade do processo. O time sabe que existe um problema, porém não consegue distinguir tempo de atendimento HTTP, chamadas ao banco e espera por dependências. Instrumentar cada aplicação com bibliotecas pode exigir mudanças e coordenação entre várias equipes.

O OpenTelemetry eBPF Instrumentation, ou OBI, oferece um ponto de entrada para obter traces e métricas de aplicações Linux compatíveis sem alterar seu código-fonte. Isso não elimina a instrumentação de negócio: cria uma primeira camada de visibilidade sobre requisições e dependências. (opentelemetry.io)

Este guia começa com um laboratório em Linux e evolui para um canário Kubernetes. O foco é instrumentação de aplicações, não detecção de ameaças com eBPF. Para esse outro recorte, veja eBPF para segurança de runtime no GKE.

Versão de referência e limites de estabilidade

Em 30 de outubro de 2026, o projeto publicou o OBI v1.0.0, usado nos exemplos. A estabilidade cobre superfícies explicitamente documentadas, como Config v2, interfaces de implantação e telemetria classificada como estável. Não significa que todas as funcionalidades ou APIs internas receberam a mesma garantia; o receiver para Collector mantém uma linha de versões separada. (github.com)

Os comandos deste artigo usam variáveis de ambiente documentadas. Não misture exemplos antigos de Config v1 com a estrutura de Config v2: nesta última, as opções específicas do OBI ficam em extensions.obi, enquanto exportadores e recursos seguem a estrutura declarativa do OpenTelemetry. (opentelemetry.io)

O que o OBI observa

O eBPF, originalmente extended Berkeley Packet Filter, permite executar programas verificados em pontos de instrumentação do Linux. O OBI utiliza essa capacidade para observar executáveis e atividade de rede e produzir telemetria de protocolos e runtimes suportados. Não é apenas um coletor de utilização do host. (opentelemetry.io)

Os principais conceitos são:

  • Seleção de processos: define quais aplicações serão instrumentadas, por exemplo por porta ou caminho do executável.
  • Span: representa uma operação observada, com duração e atributos.
  • Trace: relaciona spans por identificadores e contexto distribuído.
  • Métricas RED: taxa de requisições, erros e duração; ajudam a avaliar o comportamento do serviço.
  • OTLP: OpenTelemetry Protocol, utilizado para transportar telemetria.
  • Collector: recebe, processa e encaminha os sinais para os destinos configurados. (opentelemetry.io)

A arquitetura proposta é:

Aplicação Linux → instrumentação OBI → OTLP → OpenTelemetry Collector → backend de observabilidade

Aqui, o OBI faz a captura; o Collector concentra processamento e entrega. A transformação de atributos no pipeline é um assunto complementar, detalhado em OTTL para traces, métricas e logs.

O que não deve ser prometido

Capturar spans não garante um trace completo. Propagação de contexto depende de protocolo, runtime e topologia; proxies de camada 7 podem interromper mecanismos de propagação em nível de transporte. Observar uma conexão TLS também não significa conseguir inserir contexto nela em qualquer situação. (opentelemetry.io)

Não espere que o OBI deduza automaticamente etapas como aprovação de crédito ou cálculo de desconto. Para semântica de negócio, mantenha instrumentação manual ou agentes de linguagem. Recursos específicos também podem envolver integração com runtimes, portanto não trate zero-code como sinônimo de observação universalmente passiva. (opentelemetry.io)

1. Verifique o host antes de instalar

A matriz da versão de referência exige Linux em amd64 ou arm64, informações BTF — BPF Type Format — e permissões adequadas. O requisito geral é kernel 5.8 ou superior; existe uma exceção documentada para kernels 4.18 de distribuições da família RHEL com os backports necessários. A versão numérica isolada não comprova compatibilidade. (github.com)

Execute no host Linux:

uname -r
uname -m
test -r /sys/kernel/btf/vmlinux && echo 'BTF available'
findmnt -t tracefs
sudo ss -lntp

Use os resultados como inventário inicial, não como certificação. Confirme também políticas de segurança, disponibilidade de tracefs e capacidades exigidas pelas funcionalidades habilitadas. O OBI pode precisar acessar /proc, carregar programas BPF e anexar probes; essas operações não são autorizadas apenas por uma ServiceAccount Kubernetes. (opentelemetry.io)

Para o primeiro teste, recomendo uma máquina virtual descartável. Não comece habilitando instrumentação em todos os processos de um nó compartilhado.

2. Instale uma versão fixa do OBI

O projeto publica arquivos Linux por arquitetura e um arquivo SHA256SUMS. O procedimento abaixo fixa a versão e verifica a integridade antes da instalação. (opentelemetry.io)

set -euo pipefail
VERSION=1.0.0
case "$(uname -m)" in
  x86_64) ARCH=amd64 ;;
  aarch64|arm64) ARCH=arm64 ;;
  *) echo 'Unsupported architecture' >&2; exit 1 ;;
esac

WORKDIR=$(mktemp -d)
cd "$WORKDIR"
BASE="https://github.com/open-telemetry/opentelemetry-ebpf-instrumentation/releases/download/v${VERSION}"
curl -fLO "${BASE}/obi-v${VERSION}-linux-${ARCH}.tar.gz"
curl -fLO "${BASE}/SHA256SUMS"
sha256sum --check --ignore-missing SHA256SUMS
tar -xzf "obi-v${VERSION}-linux-${ARCH}.tar.gz"
sudo install -m 0755 obi /usr/local/bin/obi
obi --version

Para produção, minha recomendação é adicionar aprovação de origem, verificação de assinatura ou atestação conforme o procedimento do projeto e análise da lista de componentes, a SBOM. Checksum é uma etapa de integridade, não substitui toda a política de confiança da cadeia de fornecimento. (github.com)

3. Prepare um Collector local

Pré-requisito: um binário otelcol-contrib de versão fixa e aprovada já instalado. Salve o exemplo como collector-lab.yaml:

receivers:
  otlp:
    protocols:
      http:
        endpoint: 127.0.0.1:4318

processors:
  memory_limiter:
    check_interval: 1s
    limit_mib: 256
    spike_limit_mib: 64
  batch:
    timeout: 2s

exporters:
  debug:
    verbosity: detailed

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [memory_limiter, batch]
      exporters: [debug]
    metrics:
      receivers: [otlp]
      processors: [memory_limiter, batch]
      exporters: [debug]

Este pipeline de laboratório recebe OTLP/HTTP apenas em loopback, processa traces e métricas e imprime os dados. memory_limiter e batch têm funções distintas: controle de pressão de memória e agrupamento de exportação. Os valores são didáticos, não dimensionamento recomendado. O exporter debug não é armazenamento persistente e sua saída detalhada pode revelar atributos sensíveis. (opentelemetry.io)

Em um terminal dedicado:

otelcol-contrib --config=collector-lab.yaml

Não reutilize esse arquivo sem alterações em um gateway Kubernetes: um receiver em 127.0.0.1 não recebe conexões de outros Pods.

4. Instrumente um serviço HTTP simples

Em outro terminal, crie um diretório temporário sem dados reais e inicie um servidor de teste:

LAB_DIR=$(mktemp -d)
printf 'obi lab\n' > "${LAB_DIR}/index.html"
python3 -m http.server 8080 --bind 127.0.0.1 --directory "$LAB_DIR"

Em um terceiro terminal, execute o OBI:

sudo env \
  OTEL_EBPF_OPEN_PORT=8080 \
  OTEL_SERVICE_NAME=orders-lab \
  OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4318 \
  OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf \
  /usr/local/bin/obi

A porta seleciona o processo alvo; o endpoint aponta para o Collector. O protocolo é explícito para evitar confusão entre OTLP/HTTP e OTLP/gRPC. Com o endpoint compartilhado, o exportador acrescenta os caminhos de cada sinal, como /v1/traces e /v1/metrics. (opentelemetry.io)

Depois de conferir os logs de inicialização, gere tráfego em outro terminal:

for i in $(seq 1 20); do
  curl -fsS http://127.0.0.1:8080/ >/dev/null
  sleep 0.2
done
curl -sS -o /dev/null -w '%{http_code}\n' \
  http://127.0.0.1:8080/not-found

Critérios de aceitação do laboratório

Procure orders-lab na saída do Collector e confira spans, duração e atributos HTTP. Aguarde também o intervalo de exportação de métricas: por padrão, ele é de 60 segundos. O retorno 404 serve para validar o status capturado, não para presumir que toda resposta 4xx deve contar como erro de servidor. (opentelemetry.io)

Minha sequência de validação é: tráfego conhecido → processo selecionado → dados recebidos → identidade correta → atributos revisados. Um processo OBI em execução, sozinho, não comprova sucesso.

5. Evolua para um canário Kubernetes

O exemplo seguinte é de laboratório, não uma configuração pronta para produção. Ele pressupõe:

  • Um serviço existente cujo executável seja /usr/local/bin/orders-api.
  • Esse workload executando no nó escolhido para o canário.
  • Um Service otel-collector no namespace observability, com receiver OTLP/HTTP acessível na porta 4318 e pipelines de traces e métricas.
  • Aprovação para executar um agente privilegiado no namespace dedicado.

O DaemonSet permite manter um agente por nó elegível. Neste desenho, hostPID oferece visibilidade dos processos do nó e o caminho do executável restringe a seleção operacional; não é uma barreira de segurança entre tenants. (kubernetes.io)

Salve como obi-canary.yaml:

apiVersion: v1
kind: Namespace
metadata:
  name: obi-canary
  labels:
    pod-security.kubernetes.io/enforce: privileged
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: obi
  namespace: obi-canary
automountServiceAccountToken: false
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: obi
  namespace: obi-canary
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: obi
  updateStrategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
  template:
    metadata:
      labels:
        app.kubernetes.io/name: obi
    spec:
      serviceAccountName: obi
      automountServiceAccountToken: false
      hostPID: true
      nodeSelector:
        kubernetes.io/os: linux
        observability-canary: "true"
      containers:
        - name: obi
          image: otel/ebpf-instrument:v1.0.0
          imagePullPolicy: IfNotPresent
          securityContext:
            runAsUser: 0
            privileged: true
          env:
            - name: OTEL_EBPF_AUTO_TARGET_EXE
              value: /usr/local/bin/orders-api
            - name: OTEL_SERVICE_NAME
              value: orders-api
            - name: OTEL_EBPF_KUBE_METADATA_ENABLE
              value: "false"
            - name: OTEL_EXPORTER_OTLP_ENDPOINT
              value: http://otel-collector.observability.svc.cluster.local:4318
            - name: OTEL_EXPORTER_OTLP_PROTOCOL
              value: http/protobuf
            - name: OTEL_EBPF_INTERNAL_METRICS_EXPORTER
              value: prometheus
            - name: OTEL_EBPF_INTERNAL_METRICS_PROMETHEUS_PORT
              value: "6060"
          ports:
            - name: internal
              containerPort: 6060
          startupProbe:
            httpGet:
              path: /internal/metrics
              port: internal
            periodSeconds: 5
            failureThreshold: 60
          readinessProbe:
            httpGet:
              path: /internal/metrics
              port: internal
            periodSeconds: 10
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
            limits:
              cpu: 500m
              memory: 512Mi
          volumeMounts:
            - name: tracefs
              mountPath: /sys/kernel/tracing
      volumes:
        - name: tracefs
          hostPath:
            path: /sys/kernel/tracing
            type: Directory

O manifesto adapta o padrão oficial de DaemonSet. O mount de tracefs atende requisitos de anexação e propagação documentados para determinadas combinações de kernel e OBI. O endpoint /internal/metrics é o endpoint real do reporter interno. (opentelemetry.io)

As probes verificam somente a disponibilidade desse endpoint; não certificam captura nem entrega ao backend. A ausência de livenessProbe é deliberada neste canário: antes de automatizar reinícios, defina uma condição de travamento local testada. Não use indisponibilidade do Collector como motivo para reiniciar continuamente o agente.

Os recursos são valores iniciais hipotéticos. Adapte caminho, destino e capacidade. Não habilitei metadata Kubernetes: por isso não há token montado nem ClusterRole. Caso precise desse enriquecimento, utilize a configuração e as permissões list/watch documentadas, sem conceder cluster-admin. (opentelemetry.io)

O namespace permite workloads privilegiados e deve ter acesso administrativo restrito. Políticas adicionais do cluster ainda podem rejeitar o Pod; não desative políticas globais para contornar a rejeição. (kubernetes.io)

Aplique substituindo o nome do nó:

NODE=worker-canary-01
kubectl label node "$NODE" observability-canary=true --overwrite
kubectl apply -f obi-canary.yaml
kubectl -n obi-canary rollout status daemonset/obi
kubectl -n obi-canary get pods -o wide
kubectl -n obi-canary logs daemonset/obi --tail=100

Exemplo operacional: API de pedidos

Considere este cenário hipotético:

Problema → a API de pedidos usa PostgreSQL e Redis, mas a equipe não tem traces suficientes para orientar a investigação.

Solução → experimentar OBI em um nó, apenas para essa API, mantendo um grupo de controle sem o agente.

Implementação → comparar tráfego equivalente, verificar spans disponíveis e confirmar cobertura dos clientes e protocolos utilizados. A matriz documenta suporte a PostgreSQL e Redis, mas detalhes de bibliotecas, conexões existentes e volume precisam ser considerados. (github.com)

Resultado esperado → identificar quais dependências merecem investigação adicional. Isso é uma hipótese de utilidade, não um benchmark nem uma promessa de redução de latência. A ação seguinte pode ser revisar consultas, pool de conexões ou concorrência; instalar observabilidade não corrige esses problemas automaticamente.

Da demonstração à produção

Minha recomendação é aprovar a implantação somente depois de responder às perguntas abaixo.

Segurança e dados

  • Qual conjunto mínimo de capacidades atende às funcionalidades selecionadas? Substitua privileged: true quando a combinação de kernel, runtime e recursos tiver sido validada.
  • Quem pode alterar o DaemonSet, a imagem e a seleção de processos?
  • Quais atributos podem conter informações pessoais, URLs sensíveis ou consultas?
  • O tráfego remoto usa Transport Layer Security, ou TLS, com verificação de certificado?
  • Credenciais estão em Secrets ou em um mecanismo corporativo de segredos, com rotação?

Capacidades Linux e controle de acesso Kubernetes resolvem problemas diferentes. Uma ServiceAccount com permissões mínimas não neutraliza um container privilegiado. Também recomendo restringir tráfego de saída ao Collector e dependências necessárias, testando a política de rede com o plugin utilizado. (opentelemetry.io)

Disponibilidade e recuperação

Para agentes de nó, cobertura significa um agente saudável em cada nó selecionado, não duas réplicas arbitrárias disputando a mesma instrumentação. Para o gateway Collector, proponho múltiplas réplicas distribuídas entre zonas, probes, capacidade reservada e um PodDisruptionBudget compatível com a disponibilidade desejada. (kubernetes.io)

Configure filas e retries nos exportadores de produção. Se perda durante reinícios for inaceitável, avalie fila persistente com file_storage e armazenamento adequado. Filas têm limites: indisponibilidade prolongada ainda pode causar descarte. Persistência no Collector não recupera eventos que nunca chegaram até ele. (opentelemetry.io)

Mantenha configuração, dashboards e políticas versionados. Defina backup e recuperação para o armazenamento do backend, conforme retenção e criticidade, em vez de tratar o agente como banco de dados.

Performance, capacidade e custos

Proponho medir o mesmo tráfego antes e depois, acompanhando CPU, memória, latência da aplicação, reinícios, falhas de exportação e volume ingerido. Não use uma porcentagem universal de overhead. As opções de captura e os buffers fazem parte do dimensionamento. (opentelemetry.io)

Para FinOps, contabilize agentes por nó, processamento do Collector, rede entre zonas, ingestão e retenção. Estime volume diário a partir de spans por segundo e tamanho médio observado. Reduza dimensões desnecessárias antes de simplesmente aumentar recursos: cardinalidade multiplica séries e consumo. (opentelemetry.io)

Minha recomendação é não transformar identificadores de usuário ou pedido em labels de métricas. Em nós Spot, inclua churn e perda temporária de cobertura no teste. Para o gateway, escolha capacidade interruptível ou não interruptível conforme a tolerância a perda, sem pressupor que o menor preço de computação representa menor custo total.

Se houver tail sampling, escalar réplicas exige preservar o agrupamento dos spans de cada trace no componente responsável pela decisão. Não trate esse processamento como completamente sem estado. (opentelemetry.io)

Observabilidade da própria instrumentação

Separe três avaliações:

  1. Aplicação: throughput, duração e falhas relevantes ao serviço.
  2. Agente: presença por nó, consumo, reinícios e métricas internas.
  3. Pipeline: recebimento, recusas, filas, retries e falhas de exportação.

O OBI oferece métricas internas opcionais; o Collector também expõe sinais para orientar capacidade e detectar pressão. Minha recomendação adicional é um teste sintético periódico: faça uma requisição conhecida e verifique sua chegada ao destino. Endpoint de métricas acessível não substitui esse teste fim a fim. (opentelemetry.io)

Mantenha a coleta de logs como uma decisão explícita. Correlação entre logs e traces não deve ser confundida com garantia de ingestão de todos os logs da aplicação. (opentelemetry.io)

Troubleshooting

Use primeiro os comandos de inspeção:

kubectl get nodes
kubectl -n obi-canary get daemonsets,pods -o wide
kubectl -n obi-canary describe daemonset obi
kubectl -n obi-canary describe pod <pod>
kubectl -n obi-canary logs <pod> --tail=200
kubectl -n obi-canary logs <pod> --previous
kubectl get events -A --sort-by=.metadata.creationTimestamp

Substitua <pod> pelo nome real. O roteiro de diagnóstico recomendado é:

SintomaPossível causaInvestigaçãoCorreção
Nenhum Pod agendadoNó sem label, taint ou rejeição de admissãoEventos e descrição do DaemonSetCorrigir elegibilidade e aprovação, sem abrir permissões globais
OBI inicia, mas não produz spansSeleção incorreta ou ausência de tráfegoLogs, executável real e requisição controladaCorrigir seletor e repetir o teste
Erro ao carregar probesCapacidades, BTF ou política do hostLogs do agente e inventário do kernelUsar ambiente suportado e permissões justificadas
Captura sem exportaçãoDNS, rede, TLS ou protocolo incorretoLogs OBI/Collector e configuração do receiverAlinhar endpoint, protocolo e conectividade
Traces fragmentadosPropagação não suportada no caminhoComparar identificadores em cada saltoComplementar com instrumentação de linguagem
Reinícios ou degradaçãoMemória, CPU ou escopo excessivoEventos, consumo e baselineReduzir escopo, redimensionar ou interromper o canário

As limitações de probes e propagação devem ser verificadas antes de atribuir toda ausência de dados ao backend. (opentelemetry.io)

Upgrade, rollback e diferenças entre ambientes

Em desenvolvimento, uma instância, exportação local sem TLS e saída detalhada podem ser suficientes. Em produção, proponho exigir transporte protegido, capacidade medida, alertas, redundância do gateway e um procedimento de recuperação ensaiado.

Promova versões por canário e registre imagem, configuração e kernel testados. Revise alterações de telemetria antes de atualizar dashboards. A garantia da versão 1 aplica-se às superfícies classificadas como estáveis, não a toda métrica experimental. (github.com)

Para reverter uma atualização do DaemonSet ou interromper o canário:

kubectl -n obi-canary rollout undo daemonset/obi
kubectl -n obi-canary rollout status daemonset/obi

# Stop instrumentation on the selected node
kubectl label node "$NODE" observability-canary-

O undo depende de uma revisão anterior. Em GitOps, reverta também o commit ou o reconciliador poderá reaplicar a alteração. Depois da interrupção, confirme recuperação da aplicação e ausência de erros; não presuma rollback sem impacto apenas porque o código-fonte não mudou.

Quando utilizar — e quando escolher outra abordagem

OBI é um candidato para uma avaliação quando falta visibilidade inicial em serviços Linux e existe controle sobre o host. Agentes de linguagem e SDKs continuam relevantes quando são necessários detalhes de frameworks ou semântica de negócio. Ambientes sem os requisitos de kernel e privilégios não se tornam compatíveis apenas porque executam containers. (opentelemetry.io)

Minha decisão prática seria:

NecessidadeAbordagem a avaliar
Descobrir requisições e dependências com pouca alteração na aplicaçãoOBI em canário
Medir etapas específicas do domínioInstrumentação manual
Obter detalhes de frameworkAgente de linguagem compatível
Monitorar somente recursos do hostExporter ou receiver de métricas de infraestrutura
Operar onde agentes privilegiados são proibidosInstrumentação dentro da aplicação

Evite uma segunda instrumentação automática quando ela não resolve uma lacuna demonstrável. Estabeleça quem produz cada sinal e valide duplicações antes da expansão.

Resumo prático

  1. Inventarie kernel, BTF, arquitetura e permissões.
  2. Fixe a versão e selecione um único serviço.
  3. Valide captura e entrega com tráfego conhecido.
  4. Faça um canário com critérios de interrupção.
  5. Revise dados sensíveis, capacidade e custo de ingestão.
  6. Mantenha SDKs onde a semântica de negócio for necessária.
  7. Expanda somente depois de testar recuperação e rollback.

Conclusão

O valor do OBI para uma plataforma não está em coletar tudo automaticamente, mas em reduzir o esforço inicial para produzir evidências operacionais úteis. A adoção deve ser tratada como mudança de infraestrutura com impacto potencial na aplicação: escopo restrito, validação, segurança e reversibilidade.

Para DevOps, SRE e Platform Engineering, a entrega mais importante é um caminho repetível: serviço selecionado, telemetria compreensível, custo conhecido e responsabilidade operacional definida. Esse é um resultado mais sustentável do que simplesmente aumentar a quantidade de spans armazenados.

Quer aplicar isso no seu ambiente?

Agende uma conversa de 30 minutos sem compromisso. Eu olho o seu cenário e digo por onde começar.

Agendar uma conversa

Receba os novos artigos por e-mail

Um e-mail quando sair artigo novo sobre infraestrutura, backend e IA. Sem spam, cancele quando quiser.