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-1

Slug : 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 checkoutLogs 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

← Catalogue Tutoriels

Pour aller plus loin — hubs live

Retour parcours Catalogue Tutoriels — hub de la série et leçons sœurs.