OpenTelemetry is a collection of APIs, SDKs, and tools. Use it to instrument, generate, collect, and export telemetry data (metrics, logs, and traces) to help you analyze your software’s performance and behavior.
Source: https://opentelemetry.io/
Otel Diagram
Source: https://opentelemetry.io/docs/
Cenários para auto-instrumentação (Zero-code Instrumentation)
Alguns cenários podem nos levar a recorrer à instrumentação automática de aplicações. São eles:
- Não ter acesso ao código fonte;
- Falta de sponsors para um refatoramento, por não ser viável ao negócio;
- Não ser o "dono" da aplicação;
- A aplicação já executada há tempos, ninguém tem mais o contexto e o desenvolvimento foi descontinuado.
Mesmo se você se encontrar em um dos motivadores acima (ou mais de um), ainda pode haver a necessidade de observar essas aplicações.
É importante lembrar que essa abordagem de auto-instrumentação traz algumas ressalvas, como, por exemplo, o excesso de telemetria gerado pela aplicação instrumentada.
Quando temos um cenário de uma aplicação greenfield (do zero), será mais interessante já pensar na instrumentação como parte do desenvolvimento, sendo chamada de instrumentação manual e não auto-instrumentação.
Arquitetura do Lab
Nesse lab, vamos explorar a auto-instrumentação com OpenTelemetry Operator para Kubernetes.
Repositórios:
- Terraform: https://github.com/paulofponciano/EKS-Istio-Karpenter
- Stack observabilidade: https://github.com/paulofponciano/o11y-lab-prom-otel-loki-tempo
O provisionamento da infraestrutura e seus componentes, como: Cluster EKS, Istio ingress, karpenter e também a stack de observabilidade que contempla o Grafana Tempo, pode ser feito seguindo esse outro Lab - o11y: OpenTelemetry, Prometheus, Loki e Tempo no EKS [Lab Session]. Portanto, partiremos do ponto em que o EKS já está configurado e com o Grafana Tempo em execução.
Deploy do OpenTelemetry Operator
Componentes já em execução no cluster:
- Kube-prometheus-stack
- Promtail
- Grafana Loki (distributed)
- Grafana Tempo (distributed)
O que vamos usar aqui é o Grafana Tempo e o Grafana que faz parte da stack do Prometheus. No Grafana, já há um datasource do Tempo configurado.
Deploy do operator usando Helm:
git clone https://github.com/paulofponciano/o11y-lab-prom-otel-loki-tempo.git cd o11y-lab-prom-otel-loki-tempo/opentelemetry/auto-instrumentation/operator helm repo add open-telemetry https://open-telemetry.github.io/opentelemetry-helm-charts helm repo update helm install opentelemetry-operator open-telemetry/opentelemetry-operator \ --namespace opentelemetry-operator-system \ --create-namespace \ --set "manager.collectorImage.repository=otel/opentelemetry-collector-k8s" \ --set admissionWebhooks.certManager.enabled=false \ --set admissionWebhooks.autoGenerateCert.enabled=true Logs iniciais do OpenTelemetry Operator:
Deploy Otel collector
Podemos agora fazer o deploy de um custom resource que é o OpenTelemetryCollector. Basicamente, ele receberá os traces (receivers) e os enviará (exporters) para o Grafana Tempo, onde poderão ser visualizados.
kubectl apply -f otel-collector.yaml Manifesto do collector:
apiVersion: opentelemetry.io/v1beta1 kind: OpenTelemetryCollector metadata: name: otelcol namespace: o11y spec: config: receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318 processors: memory_limiter: check_interval: 1s limit_percentage: 75 spike_limit_percentage: 15 batch: send_batch_size: 10000 timeout: 10s exporters: debug: {} otlp: endpoint: tempo-distributor.o11y.svc.cluster.local:4317 tls: insecure: true service: pipelines: traces: receivers: [otlp] processors: [memory_limiter, batch] exporters: [debug, otlp] Logs iniciais do otel collector:
Exemplo Java e Otel Instrumentation
Mais um custom resource que faremos o deploy é o Instrumentation. Dentre outras configurações, nele definiremos quem será o otel collector, no caso, será o que acabamos de criar.
kubectl apply -f java-auto-instrumentation.yaml Manifesto de instrumentation:
apiVersion: opentelemetry.io/v1alpha1 kind: Instrumentation metadata: name: java-auto-instrumentation namespace: o11y spec: exporter: endpoint: http://otelcol-collector.o11y.svc.cluster.local:4318 propagators: - tracecontext - baggage sampler: type: parentbased_traceidratio argument: "1" kubectl get instrumentation -n o11y Agora podemos fazer o deploy de uma aplicação de exemplo em java (vertx-create-span):
kubectl create ns sample-api-java kubectl apply -f java-service-with-auto-instrumentation.yaml Importante notar a annotation que devemos informar no manifesto, onde é definida a instrumentation que usaremos:
# Part of the complete manifest: template: metadata: labels: app: operator-e2e-tests annotations: instrumentation.opentelemetry.io/inject-java: "o11y/java-auto-instrumentation" # ... Executando kubectl describe pod no pod da aplicação que acabou de subir, vemos que foi injetado um initContainer para auto-instrumentação:
Dentro do container:
Simulando tráfego de entrada na aplicação java:
Logs da aplicação e do otel collector:
No Grafana, visualizamos os traces recebidos através do datasource plugin do Grafana Tempo:
Exemplo Python e Otel Instrumentation
Faremos o mesmo processo de deploy, mas agora para uma app demo que simula a comunicação de microsserviços. Primeiro o apply do manifesto de instrumentation - Embora fosse possível reutilizar a Instrumentation já criada, optamos por criar uma específica para cada caso:
kubectl apply -f python-auto-instrumentation.yaml kubectl get instrumentation -n o11y Deploy app demo python:
kubectl create ns sample-api-python kubectl apply -f python-service-with-auto-instrumentation.yaml Annotation referenciando a Instrumentation:
# Part of the complete manifest: template: metadata: annotations: instrumentation.opentelemetry.io/inject-python: "o11y/python-auto-instrumentation" labels: app: microservice-1 # ... Com kubectl describe pod novamente vemos o initContainer da auto-instrumentação, agora para python:
Gerando tráfego de entrada:
No Grafana:
Podemos simular uma latência maior entre as chamadas, aumentando o 'RESPONSE_TIME' no manifesto de deploy, e reaplicar:
# Part of the complete manifest: spec: containers: - name: app image: paulofponciano/demo-ms-intercomunicacao:latest ports: - containerPort: 5000 env: - name: TITLE value: "Microservice 2" - name: RESPONSE_TIME value: "3500" # bottleneck - name: EXTERNAL_CALL_URL value: "http://microservice-3.sample-api-python.svc.cluster.local:5000" - name: EXTERNAL_CALL_METHOD value: "GET" # ... Comparando com o trace anterior (antes da alteração no RESPONSE_TIME), o ponto de gargalo fica visível:
Referências:
Dose ao vivo: aula prática de OpenTelemetry Operator
OpenTelemetry - Injecting Auto-instrumentation
OpenTelemetry Operator for Kubernetes
Keep shipping! 🐳

























Top comments (0)