Sommaire
Le tracing distribué répond à la question que les métriques et les logs ne peuvent pas entièrement résoudre : dans une requête qui a touché sept services sur 400ms, lequel est responsable de 320ms de cette latence ? Les métriques vous disent que le P99 global a dégradé. Les logs vous disent que chaque service a reçu la requête. Seule une trace vous montre l’exact span où le temps a été perdu.
OpenTelemetry est devenu la réponse standardisée CNCF pour la collecte de traces. Il fournit des API indépendantes du langage, des agents d’auto-instrumentation pour les principaux runtimes, un protocole fil vendor-neutral (OTLP), et le Collector comme pipeline de traitement flexible. Cet article couvre le déploiement d’OpenTelemetry sur VKS : la configuration du Collector, la mise en place de l’auto-instrumentation, la stratégie d’échantillonnage, et l’intégration avec les exemplars Prometheus qui crée la boucle de corrélation métrique-vers-trace.
Le modèle de données OTel pour les traces
La spécification OTel pour les traces définit les concepts fondamentaux suivants :
Trace — un ensemble de spans partageant un span racine et un traceId commun (identifiant aléatoire de 16 octets). La trace représente une opération distribuée de bout en bout.
Span — l’unité atomique de travail dans une trace. Chaque span porte :
traceId— identifie la tracespanId— identifie de façon unique ce span (8 octets)parentSpanId— référence le span parent (absent pour les spans racines)name— nom d’opération lisible (ex.HTTP GET /api/users)kind— un parmiINTERNAL,SERVER,CLIENT,PRODUCER,CONSUMERstartTime/endTime— timestamps en nanosecondesstatus—OK,ERROR, ouUNSETattributes— paires clé-valeur (max 128 par span dans les SDK OTel)events— annotations horodatées dans le spanlinks— références à des spans liés causalement dans d’autres traces
Propagation de contexte — le mécanisme qui passe le contexte de trace (traceId + spanId) à travers les frontières de service. Les requêtes HTTP utilisent le header traceparent (standard W3C Trace Context). Les messages Kafka utilisent le header W3C Baggage. gRPC utilise les métadonnées. Les agents d’auto-instrumentation gèrent automatiquement l’injection et l’extraction du contexte.
Le protocole OTLP
L’OpenTelemetry Protocol (OTLP) est le format fil standard pour les signaux OTel. Il supporte gRPC (port par défaut 4317) et HTTP/Protobuf (port par défaut 4318). OTLP transporte les trois types de signaux (traces, métriques, logs) sur la même connexion.
# Configuration du receiver OTLP dans l'OTel Collector
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
Le SDK envoie les spans par batch via OTLP. Le Collector les reçoit, les traite et les exporte. Ce découplage est la valeur centrale de l’architecture Collector — les applications n’ont besoin de connaître que l’endpoint du Collector, pas la topologie backend.
Déployer l’OpenTelemetry Collector
Le pipeline OTel Collector comporte quatre types de composants : receivers, processors, exporters et extensions. Le schéma de configuration du Collector les définit comme des maps nommées.
helm repo add open-telemetry https://open-telemetry.github.io/opentelemetry-helm-charts
helm repo update
helm upgrade --install otel-collector open-telemetry/opentelemetry-collector \
--namespace observability \
--create-namespace \
--values otel-collector-values.yaml
# otel-collector-values.yaml
mode: deployment
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_mib: 800
spike_limit_mib: 200
batch:
send_batch_size: 512
timeout: 5s
tail_sampling:
decision_wait: 10s
num_traces: 100000
policies:
- name: errors-policy
type: status_code
status_code: { status_codes: [ERROR] }
- name: slow-traces-policy
type: latency
latency: { threshold_ms: 1000 }
- name: probabilistic-policy
type: probabilistic
probabilistic: { sampling_percentage: 5 }
exporters:
otlp/tempo:
endpoint: tempo.observability.svc.cluster.local:4317
tls:
insecure: true
prometheusremotewrite:
endpoint: http://kube-prometheus-stack-prometheus.monitoring.svc.cluster.local:9090/api/v1/write
extensions:
health_check:
endpoint: 0.0.0.0:13133
service:
extensions: [health_check]
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, tail_sampling, batch]
exporters: [otlp/tempo]
metrics:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [prometheusremotewrite]
Le tail sampling nécessite un routage stateful
Le processor tail_sampling doit voir tous les spans d’une trace avant de prendre une décision d’échantillonnage. Dans un déploiement Collector multi-réplicas, tous les spans du même traceId doivent être routés vers la même instance Collector. Utilisez le loadbalancingexporter ou un load balancer sticky devant les réplicas Collector, ou basculez vers le head-based sampling si vous pouvez tolérer des décisions prises au début de la trace.
Auto-instrumentation avec l’OTel Operator
L’OpenTelemetry Operator pour Kubernetes permet une instrumentation zéro-code en injectant des agents d’auto-instrumentation spécifiques au langage comme init containers. Cela évite de demander aux équipes applicatives de modifier leur code.
helm upgrade --install opentelemetry-operator open-telemetry/opentelemetry-operator \
--namespace observability \
--set "manager.collectorImage.repository=otel/opentelemetry-collector-contrib"
Créez une ressource Instrumentation qui définit la configuration du SDK :
apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
name: otel-instrumentation
namespace: production
spec:
exporter:
endpoint: http://otel-collector.observability.svc.cluster.local:4318
propagators:
- tracecontext
- baggage
sampler:
type: parentbased_traceidratio
argument: "0.10" # 10% head-based sampling au niveau SDK
java:
image: ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-java:2.x
env:
- name: OTEL_INSTRUMENTATION_JDBC_ENABLED
value: "true"
python:
image: ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-python:0.x
nodejs:
image: ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-nodejs:0.x
go:
image: ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-go:0.x
Annotez les déploiements pour activer l’auto-instrumentation :
# Dans les métadonnées du template pod du Deployment
annotations:
instrumentation.opentelemetry.io/inject-java: "production/otel-instrumentation"
Le webhook Operator intercepte la création de pod et injecte l’init container de l’agent et les variables d’environnement requises (OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_SERVICE_NAME, OTEL_RESOURCE_ATTRIBUTES). Les pods applicatifs démarrent instrumentés sans aucun changement de code.
Stratégie d’échantillonnage
L’échantillonnage est la pratique d’enregistrer seulement une fraction des traces. Sans échantillonnage, un système en production produisant 10 000 requêtes par seconde génère 10 000 spans racines par seconde — beaucoup trop pour stocker et interroger efficacement.
Décision prise au début de la trace. Le span racine décide si la trace est échantillonnée, et tous les spans en aval héritent de cette décision via la propagation de contexte. Simple et stateless — aucune coordination Collector requise.
Limitation : vous ne pouvez pas retrospectivement garder une trace parce qu’elle s’est avérée intéressante (lente, en erreur). Vous vous engagez avant de connaître le résultat. Utilisez un taux faible (1 à 10%) pour une visibilité de base.
Décision prise après la complétion de la trace. Le Collector met en buffer tous les spans pendant une fenêtre configurable (10 à 30 secondes), puis applique des politiques : garder toutes les traces en erreur, toutes les traces lentes, et N% du reste.
Avantage : vous ne ratez jamais une trace d’erreur ou lente. Le sous-ensemble représentatif conservé contient exactement les traces qui comptent opérationnellement.
Limitation : stateful, nécessite de router tous les spans de la même trace vers la même instance Collector.
Hérite la décision d’échantillonnage du span parent. Si le span racine est échantillonné, tous les spans enfants le sont. Sinon, aucun ne l’est. C’est le défaut du SDK OTel (parentbased_traceidratio) et permet un échantillonnage cohérent à travers des flottes de services hétérogènes.
Corrélation exemplar : métriques vers traces
Les exemplars Prometheus sont le mécanisme qui connecte une observation d’histogramme à une trace spécifique. Quand une application enregistre une latence de requête dans un bucket d’histogramme, elle peut attacher un traceId à cette mesure. Prometheus stocke l’exemplar à côté du bucket d’histogramme. Grafana rend l’exemplar comme une superposition cliquable sur le graphe, pointant vers la trace dans Tempo.
L’agent Java OTel attache automatiquement des exemplars aux histogrammes Micrometer/Prometheus quand Prometheus et l’instrumentation OTel sont tous les deux actifs. Pour l’instrumentation manuelle, utilisez l’API exemplar du SDK :
// Java : attacher un exemplar à une observation d'histogramme Prometheus
histogram.record(latencyMs, Attributes.of(
AttributeKey.stringKey("http.method"), "GET",
AttributeKey.stringKey("http.route"), "/api/products"
));
// Le SDK injecte automatiquement le contexte de trace courant comme exemplar
Activez le stockage des exemplars dans Prometheus (enableFeatures: [exemplar-storage] dans les valeurs kube-prometheus-stack) et configurez la source de données Tempo de Grafana avec la requête TraceQL exemplar. Le résultat : depuis un panneau Grafana montrant la latence P99, cliquez sur n’importe quel pic et atterrissez directement sur la trace responsable.
Tempo comme backend de traces
Grafana Tempo stocke les traces en object storage (S3, GCS ou vSAN Object Storage) et fournit une API de requête TraceQL consommée exclusivement par Grafana Explore. Il n’a pas d’UI de traces standalone.
helm upgrade --install tempo grafana/tempo \
--namespace observability \
--set storage.trace.backend=local \
--set storage.trace.local.path=/var/tempo \
--set persistence.enabled=true \
--set persistence.storageClassName=vsan-default-storage-policy \
--set persistence.size=50Gi
Pour de grands volumes de traces, basculez storage.trace.backend vers s3 et configurez un endpoint compatible S3. Le vSAN Object Storage avec compatibilité API S3 fonctionne comme backend, gardant les données de traces sur site.
Références.
- Spécification OTel — Tracing — modèle de données span, propagation de contexte, échantillonnage
- Spécification OTLP — protocole fil pour traces, métriques et logs
- Configuration OTel Collector — receivers, processors, exporters, pipeline de service
- Documentation OTel Operator — auto-instrumentation, CRD Instrumentation
- Documentation Grafana Tempo — backends de stockage, TraceQL, intégration Exemplar
Reçois le prochain par email
Les nouveaux articles et séries, envoyés à leur publication. Aucun autre courrier.



