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 -lntpUse 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 --versionPara 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.yamlNã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/obiA 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-foundCrité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-collectorno namespaceobservability, 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: DirectoryO 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=100Exemplo 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: truequando 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:
- Aplicação: throughput, duração e falhas relevantes ao serviço.
- Agente: presença por nó, consumo, reinícios e métricas internas.
- 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.creationTimestampSubstitua <pod> pelo nome real. O roteiro de diagnóstico recomendado é:
| Sintoma | Possível causa | Investigação | Correção |
|---|---|---|---|
| Nenhum Pod agendado | Nó sem label, taint ou rejeição de admissão | Eventos e descrição do DaemonSet | Corrigir elegibilidade e aprovação, sem abrir permissões globais |
| OBI inicia, mas não produz spans | Seleção incorreta ou ausência de tráfego | Logs, executável real e requisição controlada | Corrigir seletor e repetir o teste |
| Erro ao carregar probes | Capacidades, BTF ou política do host | Logs do agente e inventário do kernel | Usar ambiente suportado e permissões justificadas |
| Captura sem exportação | DNS, rede, TLS ou protocolo incorreto | Logs OBI/Collector e configuração do receiver | Alinhar endpoint, protocolo e conectividade |
| Traces fragmentados | Propagação não suportada no caminho | Comparar identificadores em cada salto | Complementar com instrumentação de linguagem |
| Reinícios ou degradação | Memória, CPU ou escopo excessivo | Eventos, consumo e baseline | Reduzir 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:
| Necessidade | Abordagem a avaliar |
|---|---|
| Descobrir requisições e dependências com pouca alteração na aplicação | OBI em canário |
| Medir etapas específicas do domínio | Instrumentação manual |
| Obter detalhes de framework | Agente de linguagem compatível |
| Monitorar somente recursos do host | Exporter ou receiver de métricas de infraestrutura |
| Operar onde agentes privilegiados são proibidos | Instrumentaçã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
- Inventarie kernel, BTF, arquitetura e permissões.
- Fixe a versão e selecione um único serviço.
- Valide captura e entrega com tráfego conhecido.
- Faça um canário com critérios de interrupção.
- Revise dados sensíveis, capacidade e custo de ingestão.
- Mantenha SDKs onde a semântica de negócio for necessária.
- 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.
Artigos relacionados
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 conversaReceba os novos artigos por e-mail
Um e-mail quando sair artigo novo sobre infraestrutura, backend e IA. Sem spam, cancele quando quiser.