Grafana Loki Tempo : construire une stack d’observabilité LGT
À la fin de ce tutoriel, vous saurez déployer une stack Grafana + Loki + Tempo, collecter logs et traces avec Grafana Alloy, recevoir de l’OTLP sur Kubernetes et passer d’une trace lente aux logs du même service dans Grafana.
Niveau : Intermédiaire · Temps estimé : 60–90 min · Versions cibles : Kubernetes 1.31+ · Helm 3 · Grafana Alloy · Loki et Tempo monolithiques pour le lab · Dernière vérification : 2026-09-11 · Région :
ca-central-1Slug :
wow-grafana-loki-tempo· Série : WOW Observability · Mot-clé SEO : Grafana Loki Tempo · Publish : HOLD
Prérequis
- Cluster Kubernetes jetable (local ou EKS lab
ca-central-1) +kubectl+ Helm 3 - ~4 Go RAM, accès registries, droits namespace/Service/ConfigMap
- Notions Pod, labels, logs
stdout, traces/spans, OTLP - Aucun secret prod ; contexte EKS dédié + identité AWS lab
export AWS_PROFILE=lab
export AWS_DEFAULT_REGION=ca-central-1
aws sts get-caller-identity
kubectl config current-context
kubectl get nodes
helm version
Coût estimé : quasi nul en kind/k3d. EKS est facturé : cluster jetable, budget, destroy après lab. Publish HOLD.
Ce que nous allons construire
Application de démonstration sur Kubernetes — ca-central-1
├── stdout JSON ───────────────► Alloy ─► Loki
└── traces OTLP/HTTP ──────────► Alloy ─► Tempo
│
▼
Grafana Explore
trace_id : trace ⇄ logs
LGT = Loki + Grafana + Tempo. Grafana explore ; Loki indexe surtout des labels et garde les lignes ; Tempo stocke les traces. Alloy agit comme agent OpenTelemetry : OTLP, découverte Pods, routage.
Architecture monolithique et éphémère pour apprendre. En prod : stockage objet, réplication, quotas, auth, sauvegardes. Ne copiez pas ce design pour une charge critique.
Étape 1 — Créer le namespace et ajouter les dépôts Helm
kubectl create namespace observability
helm repo add grafana https://grafana.github.io/helm-charts
helm repo update
Vérifiez le contexte lab. Le namespace isole sans être une frontière de sécurité. Versionnez les values Helm, jamais les mots de passe réels.
Étape 2 — Installer Loki pour les logs
Créez loki-values.yaml pour un déploiement simple sans stockage cloud :
deploymentMode: SingleBinary
loki:
auth_enabled: false
commonConfig:
replication_factor: 1
storage:
type: filesystem
singleBinary:
replicas: 1
persistence:
enabled: false
read:
replicas: 0
write:
replicas: 0
backend:
replicas: 0
helm upgrade --install loki grafana/loki
--namespace observability -f loki-values.yaml --wait
kubectl -n observability get pods -l app.kubernetes.io/name=loki
Loki n’est pas Elasticsearch : n’indexez pas user_id, request_id ou trace_id en labels (cardinalité). Preférez namespace, app, environment. Le trace_id reste dans le JSON et s’extrait à la requête.
Étape 3 — Installer Tempo et exposer OTLP
Créez tempo-values.yaml :
tempo:
reportingEnabled: false
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
retention: 1h
persistence:
enabled: false
service:
type: ClusterIP
helm upgrade --install tempo grafana/tempo
--namespace observability -f tempo-values.yaml --wait
kubectl -n observability get pods,svc | grep tempo
Tempo agrège les spans en traces. OTLP/gRPC : 4317 ; OTLP/HTTP : 4318. On envoie d’abord vers Alloy pour centraliser filtrage, enrichissement et routage.
Étape 4 — Déployer Alloy comme passerelle OTLP et collecteur de logs
Le chart Alloy monte une configuration River. Créez alloy-values.yaml :
alloy:
configMap:
content: |-
logging { level = "info" }
otelcol.receiver.otlp "apps" {
grpc { endpoint = "0.0.0.0:4317" }
http { endpoint = "0.0.0.0:4318" }
output { traces = [otelcol.exporter.otlp.tempo.input] }
}
otelcol.exporter.otlp "tempo" {
client {
endpoint = "tempo.observability.svc.cluster.local:4317"
tls { insecure = true }
}
}
discovery.kubernetes "pods" { role = "pod" }
discovery.relabel "pod_logs" {
targets = discovery.kubernetes.pods.targets
rule {
source_labels = ["__meta_kubernetes_pod_phase"]
regex = "Running"
action = "keep"
}
rule {
source_labels = ["__meta_kubernetes_namespace"]
target_label = "namespace"
}
rule {
source_labels = ["__meta_kubernetes_pod_label_app"]
target_label = "app"
}
}
loki.source.kubernetes "pods" {
targets = discovery.relabel.pod_logs.output
forward_to = [loki.write.local.receiver]
}
loki.write "local" {
endpoint { url = "http://loki.observability.svc.cluster.local:3100/loki/api/v1/push" }
}
extraPorts:
- name: otlp-grpc
port: 4317
targetPort: 4317
- name: otlp-http
port: 4318
targetPort: 4318
helm upgrade --install alloy grafana/alloy
--namespace observability -f alloy-values.yaml --wait
kubectl -n observability get pods,svc -l app.kubernetes.io/instance=alloy
kubectl -n observability logs deploy/alloy --tail=50
Les noms varient selon le chart : kubectl get all avant de conclure. En prod : limites mémoire, retry, batch, NetworkPolicy, plusieurs réplicas.
Étape 5 — Générer une trace et un log corrélés
Ce Pod Python crée une trace OTLP/HTTP puis un log JSON avec le même trace_id. pip au démarrage = lab seulement ; image immuable en prod.
apiVersion: v1
kind: Pod
metadata:
name: telemetry-demo
namespace: observability
labels:
app: telemetry-demo
spec:
restartPolicy: Never
containers:
- name: app
image: python:3.12-slim
command: ["sh", "-c"]
args:
- |
pip install --no-cache-dir opentelemetry-sdk opentelemetry-exporter-otlp-proto-http &&
python - <<'PY'
import json, time
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
p=TracerProvider(); trace.set_tracer_provider(p)
p.add_span_processor(BatchSpanProcessor(OTLPSpanExporter(
endpoint="http://alloy.observability.svc.cluster.local:4318/v1/traces")))
with trace.get_tracer("wow-lab").start_as_current_span("checkout") as span:
tid=format(span.get_span_context().trace_id,"032x")
print(json.dumps({"level":"info","service":"telemetry-demo",
"message":"commande validée","trace_id":tid}), flush=True)
time.sleep(2)
p.shutdown()
PY
kubectl apply -f telemetry-demo.yaml
kubectl -n observability wait pod/telemetry-demo
--for=jsonpath='{.status.phase}'=Succeeded --timeout=180s
kubectl -n observability logs telemetry-demo
Copiez le trace_id. En échec : kubectl describe pod telemetry-demo (DNS, PyPI, endpoint Alloy).
Étape 6 — Installer Grafana et déclarer Loki/Tempo
Créez grafana-values.yaml :
adminPassword: wow-lab-change-me
persistence:
enabled: false
datasources:
datasources.yaml:
apiVersion: 1
datasources:
- name: Loki
type: loki
access: proxy
url: http://loki.observability.svc.cluster.local:3100
jsonData:
derivedFields:
- name: TraceID
matcherRegex: '"trace_id":"([a-f0-9]{32})"'
datasourceUid: tempo
url: '$${__value.raw}'
- name: Tempo
uid: tempo
type: tempo
access: proxy
url: http://tempo.observability.svc.cluster.local:3200
jsonData:
tracesToLogsV2:
datasourceUid: Loki
filterByTraceID: true
spanStartTimeShift: -5m
spanEndTimeShift: 5m
helm upgrade --install grafana grafana/grafana
--namespace observability -f grafana-values.yaml --wait
kubectl -n observability port-forward svc/grafana 3000:80
Ouvrez http://localhost:3000 (admin + mot de passe lab) → Explore. Loki : {namespace="observability", app="telemetry-demo"}. Le champ TraceID doit lier Tempo. Inversement : cherchez le trace_id dans Tempo → span checkout → Logs for this span. Cette corrélation coupe le MTTR.
Étape 7 — Valider, sécuriser et nettoyer le lab
Checklist HowTo :
- [ ] Loki accepte les logs sans label à forte cardinalité.
- [ ] Tempo reçoit la trace OTLP via Alloy.
- [ ] Le log JSON contient exactement le même
trace_id. - [ ] Grafana passe du log à la trace et de la trace aux logs.
- [ ] Les workloads restent dans la région cible
ca-central-1.
En réel : TLS, auth/SSO Grafana, object storage chiffré, rétention, quotas, filtrage PII, attributs service.name / deployment.environment et propagation W3C.
kubectl delete namespace observability
# Si le cluster EKS est jetable, détruisez-le avec son outil IaC.
Supprimer le namespace efface le stockage éphémère. Vérifiez volumes, LB ou buckets si vous avez adapté les values.
Erreurs fréquentes
| Symptôme | Cause probable | Correction |
|---|---|---|
| Aucun log dans Loki | RBAC, découverte ou labels absents | Lire les logs Alloy et tester {namespace="observability"} |
| Tempo reste vide | Mauvais port ou protocole OTLP | Vérifier 4317 gRPC contre 4318/v1/traces HTTP |
| Lien TraceID absent | Regex incompatible avec le JSON | Comparer la ligne brute et tester 32 caractères hexadécimaux |
| « connection refused » | Nom DNS ou Service incorrect | kubectl get svc -n observability puis corriger l’URL |
| Loki consomme trop | Labels dynamiques à forte cardinalité | Garder le trace ID dans le contenu, pas dans l’index |
| Corrélation imprécise | Horloges ou fenêtre temporelle | Synchroniser les nœuds et élargir les shifts |
Quiz (5 questions)
1. Quel composant stocke les traces ?
A. Loki · B. Tempo · C. Grafana
2. Quel protocole standard transporte la télémétrie du lab ?
A. FTP · B. OTLP · C. SMTP
3. Où placer le trace_id côté Loki ?
A. En label systématique · B. Dans le log structuré · C. Dans le nom du Pod
4. À quoi sert Alloy ici ?
A. Créer EKS · B. Collecter et router logs et traces · C. Remplacer Grafana
5. Quelle région encadre le lab WOW ?
A. us-east-1 · B. eu-west-1 · C. ca-central-1
Réponses : 1-B · 2-B · 3-B · 4-B · 5-C
FAQ
Grafana Loki Tempo remplace-t-il Prometheus ?
Non. LGT = UI + logs + traces. Prometheus/Mimir = métriques. Les trois signaux classiques se complètent ; ajoutez profils/événements au besoin.
Pourquoi Alloy plutôt que plusieurs agents ?
Alloy unifie pipelines OTel et composants Grafana. Moins d’agents, mais il faut toujours gouverner files d’attente, mémoire, backpressure, sécu et upgrades.
Peut-on utiliser S3 avec Loki et Tempo en ca-central-1 ?
Oui pour une archi durable. Buckets séparés, chiffrement, BPA, IAM least privilege, lifecycle, tags FinOps. Pas le filesystem du lab.
Comment corréler automatiquement logs et traces ?
Propagez W3C, injectez trace_id (et span_id) dans les logs structurés, puis derived fields Loki + tracesToLogsV2 Tempo.
OTLP/HTTP ou OTLP/gRPC ?
Les deux. gRPC efficace en long-lived ; HTTP plus simple derrière proxies. Alignez protocole, port, chemin et TLS.
Cette architecture est-elle prête pour la production ?
Non : flux pédagogique. Prod = HA, object storage, capacity planning, multi-tenancy, réseau, SSO, backups, alertes pipeline, tests de restore.
Pour aller plus loin
- Ajouter métriques et exemplars avec OpenTelemetry et Prometheus.
- Instrumenter plusieurs services afin de visualiser une vraie trace distribuée.
- Déployer les composants par GitOps avec Argo CD.
- Protéger les secrets avec Vault ou External Secrets.
- Remplacer le stockage éphémère par S3 dans
ca-central-1, avec chiffrement et lifecycle.
Maillage série WOW
| Précédent | OpenTelemetry : stack d’observabilité |
| Suivant | Prometheus et alerting Kubernetes |
| Aussi | Platform Engineering 2026 · Argo CD GitOps · Vault |
Meta publication SEO — Publish HOLD
- Title SEO : Grafana Loki Tempo : stack observabilité Kubernetes
- Meta description : Déployez Grafana, Loki, Tempo et Alloy sur Kubernetes : lab OTLP, logs structurés et corrélation traces/logs en ca-central-1.
- Focus keyword : Grafana Loki Tempo
- Secondaires : stack LGT, Grafana Alloy, OTLP Kubernetes, corrélation traces logs, observabilité Kubernetes
- Schema : HowTo + FAQPage + Article
- Image :
assets/web/devopelastichayway/cover-wow-grafana-loki-tempo-1200x630.webp - Alt image : Architecture Grafana Loki Tempo et Alloy sur Kubernetes
- Catégorie : WOW / Observability · Niveau : Intermédiaire
- URL cible : https://devopelastichayway.com/tutoriels/wow-grafana-loki-tempo/
- Mis à jour : 2026-09-11 · Région :
ca-central-1 - Statut : Publish HOLD — brouillon uniquement
Pour aller plus loin — hubs live
Retour parcours Catalogue Tutoriels — hub de la série et leçons sœurs.