Lab 1 — Démarrage de la stack d'observabilité

Bienvenue dans l’équipe SRE de l’Astronomy Shop 🔭 — une boutique e-commerce composée d’une vingtaine de micro-services, instrumentée avec OpenTelemetry (démo officielle).

Dans ce premier lab, entièrement guidé, vous démarrez la plateforme d’observabilité complète : le collecteur OpenTelemetry, Grafana, Jaeger (traces), Prometheus (métriques) et OpenSearch (logs), ainsi que la boutique elle-même et son générateur de trafic.

💡 Toute la stack tourne dans un cluster Kubernetes local (Kind). Kubernetes n’est pas le sujet de cette formation : toutes les commandes kubectl sont fournies, avec leur explication.

Prérequis

  • Docker installé et fonctionnel (docker ps ne renvoie pas d’erreur).
  • kubectl, helm et ktbx installés.
  • kind ≥ v0.27 (kind version) — les versions plus anciennes ne savent pas charger d’images dans les nœuds récents (erreur failed to detect containerd snapshotter). Mise à jour : go install sigs.k8s.io/kind@v0.30.0.
  • Le dépôt de la formation cloné :
git clone https://github.com/k8s-school/otel-labs.git
cd otel-labs

Étapes

  1. Créer le cluster et installer la démo OpenTelemetry :
./scripts/up.sh

🏫 Serveur partagé : si le formateur vous a fourni un compte student<N> sur un serveur commun, la commande est la même, mais elle va beaucoup plus vite : votre cluster a généralement été créé la veille, avec les images déjà chargées. Le script le réutilise et n’a plus que la démo à installer — une minute environ.

Vous partagez la machine avec les autres participants : pour que vos accès n’entrent pas en conflit avec les leurs, chacun écoute sur sa propre adresse de boucle locale au lieu de localhost — student3 sur 127.0.0.3, alias localhost3. Les ports, eux, sont les mêmes pour tout le monde (8080 pour les UIs). Une variable déjà présente dans votre shell porte ce nom : $PF_HOST, celui de vos URLs. open-ui.sh les affiche — ouvrez-les depuis le navigateur du serveur (Guacamole).

Sur un poste neuf, comptez quelques minutes : c’est le téléchargement des images. Pendant ce temps, regardez ce que fait le script, dans l’ordre :

  1. il vérifie si le cluster Kind à votre nom existe. S’il est là, il le réutilise ; sinon il le crée (ktbx create -s). Il ne le détruit jamais — vous pouvez donc relancer up.sh autant de fois que vous voulez sans perdre votre travail. Pour supprimer le cluster, il faut le demander explicitement, avec ./scripts/down.sh ;
  2. il pré-télécharge les images de la démo sur la machine et les injecte dans le cluster (scripts/preload-images.sh) — celles que le cluster possède déjà sont sautées ;
  3. il installe le chart Helm open-telemetry/opentelemetry-demo dans le namespace otel-demo — c’est la démo officielle OpenTelemetry, l’« Astronomy Shop ».
Que contient le namespace otel-demo ?

Le chart Helm déploie :

  • la boutique : une vingtaine de micro-services polyglottes (Go, Java, Python, .NET, Rust…), Kafka, PostgreSQL, Valkey ;
  • le load generator, qui simule des clients en continu — vous aurez donc toujours des données à observer ;
  • la chaîne d’observabilité : collecteur OpenTelemetry (DaemonSet), Jaeger, Prometheus, OpenSearch et Grafana, déjà câblés entre eux.

Le détail service par service (langage, type d’instrumentation utilisée) : Language feature reference.

  1. Vérifier que tous les pods sont démarrés :
kubectl get pods -n otel-demo

kubectl get pods -n otel-demo liste les conteneurs qui tournent dans le namespace otel-demo. Tous doivent être en état Running avec READY 1/1.

Combien de micro-services applicatifs identifiez-vous ? Lesquels tournent sur la JVM ?

Réponse

Une vingtaine de pods applicatifs. Deux tournent sur la JVM :

  • ad (Ad Service), écrit en Java et instrumenté avec l’agent Java OpenTelemetry : c’est notre service de référence pour le Lab 2 ;
  • fraud-detection, écrit en Kotlin — un autre langage, mais la même JVM et le même agent Java.

kubectl ne dit pas dans quel langage un service est écrit : il ne voit que des conteneurs, et les images de la démo portent toutes le même nom. Le langage se lit dans la Language feature reference de la démo — ou, une fois la télémétrie en place, dans l’attribut telemetry.sdk.language que chaque SDK ajoute à ses données : il vaut java pour ces deux services.

  1. Accéder aux interfaces web :
./scripts/open-ui.sh

Ce script ouvre tous les accès dont les labs ont besoin — les UIs sur le port 8080 (derrière le proxy frontal : la boutique, Grafana, Jaeger…), Prometheus, OpenSearch, les zPages du collecteur et votre review-service — puis rend la main : il travaille en arrière-plan et vous affiche vos URLs exactes. Il les rouvre tout seul à chaque redéploiement, et ./scripts/open-ui.sh -s les ferme.

Un accès qui n’existe pas encore n’est pas une erreur : le review-service est celui que vous déploierez au Lab 2, son URL répondra à ce moment-là.

Utilisez les URLs que le script vient d’afficher, et elles seules :

  Astronomy Shop   http://localhost1:8080/        <- exemple pour student1
  Grafana          http://localhost1:8080/grafana/
  Jaeger           http://localhost1:8080/jaeger/ui/
  Load generator   http://localhost1:8080/loadgen/

⚠️ N’écrivez jamais localhost en dur sur le serveur partagé. Chaque compte a son adresse (student1 → localhost1, student2 → localhost2…), et localhost tout court est celle de student1. Un participant qui tape http://localhost:8080/ tombe donc sur la boutique de son voisin — elle répond, tout a l’air normal, et il cherchera ensuite sa trace dans le Jaeger de quelqu’un d’autre.

Le même piège vaut pour les URLs affichées par Helm à la fin de l’installation : elles annoncent http://localhost:8080 parce que le chart ne connaît pas votre compte. Fiez-vous à open-ui.sh, pas à elles.

Sur un poste individuel, $PF_HOST vaut simplement localhost et la question ne se pose pas.

  1. Générer votre propre trafic :

Ouvrez la boutique, choisissez un télescope et passez une commande complète (panier → checkout).

⚠️ Vous n’êtes pas seul à commander : la démo embarque un load generator (Locust, 10 utilisateurs virtuels démarrés automatiquement) qui navigue et passe des commandes en continu, pour que la plateforme ait toujours des données à observer. Résultat : Jaeger contient en permanence des dizaines de traces de checkout qui ne sont pas les vôtres — et elles ressemblent beaucoup aux vôtres.

Pour isoler votre commande, mettez le générateur en pause avant de commander :

  • ouvrez le load generator (l’URL /loadgen/ affichée par open-ui.sh), cliquez sur Stop ;
  • attendez ~30 s (le temps que les requêtes en cours se terminent), puis notez l’heure et passez votre commande ;
  • relancez le générateur après l’étape 5 — bouton New en haut à droite, puis Start dans la fenêtre Start new load test : les labs suivants ont besoin de ce trafic de fond.
  1. Retrouver votre commande dans Jaeger :

Dans Jaeger, cherchez les traces du service checkout (opération oteldemo.CheckoutService/PlaceOrder) et ouvrez la plus récente — celle dont l’horodatage correspond à votre clic.

⏱️ Une trace met quelques secondes à devenir visible (le SDK et le collecteur envoient par paquets, pas span par span). Si vous ne la voyez pas tout de suite, relancez la recherche (Find Traces) au bout de 5 à 10 secondes.

💡 Si vous n’avez pas arrêté le load generator, triez par Most Recent et repérez la trace à l’heure de votre commande — c’est le critère le plus fiable. Indice complémentaire : les traces issues des requêtes HTTP du générateur contiennent un span du service load-generator (visible dans les badges de services de la liste de résultats), que les vôtres n’ont pas.

Combien de services différents cette trace traverse-t-elle ? Que représente chaque barre horizontale ?

Réponse

La trace de checkout traverse une douzaine de services : frontend → checkout → cart, currency, payment, shipping, quote, email, product-catalog, flagd, valkey-cart.

Chaque barre horizontale est un span : une opération unitaire (requête HTTP, appel gRPC, requête SQL, publication Kafka) avec sa durée. L’ensemble des spans liés forme la trace : le parcours complet de la requête à travers le système distribué.

Le dernier span de la trace est publish orders : checkout dépose la commande dans Kafka. C’est le seul span Kafka de la trace.

Et les services qui lisent cette file, accounting et fraud-detection ? Ils ne sont pas dans votre trace. Un consommateur de file ne peut pas être un « enfant » de la requête HTTP : celle-ci est déjà terminée quand il dépile le message. Il ouvre donc sa propre trace, rattachée à la vôtre par un lien. Pour la voir : cherchez le service fraud-detection, opération process orders, et ouvrez la trace la plus récente — la section References du span y affiche l’identifiant de votre trace de checkout, et un clic vous y ramène.

  1. Une première métrique dans Grafana :

Dans Grafana, ouvrez le dashboard Demo Dashboard (dossier General). Observez le taux de requêtes et les latences par service — c’est le trafic du load generator que vous voyez en direct.

  1. Le fil rouge — un service invisible :

L’équipe Java vient de livrer le micro-service review-service (avis produits). Cherchez-le dans Jaeger (liste des services) et dans Grafana.

Réponse

Il n’y est pas ! review-service n’est même pas encore déployé — et surtout, il n’est pas instrumenté : même déployé, il n’émettrait aucune télémétrie.

⚠️ Ne le confondez pas avec product-reviews, que la liste de Jaeger contient bel et bien. C’est un service de la démo, écrit en Python, qui gère les avis de la boutique. Le vôtre s’appelle review-service, il est en Java, et il n’apparaîtra qu’au Lab 2. Les deux écrivent d’ailleurs dans la même base, dans deux tables différentes — un détail qui resservira au Lab 3.

C’est tout l’objet des prochains labs : le rendre observable de bout en bout, sans modifier son code pour commencer (Lab 2).

Livrable

Une capture d’écran d’une trace de checkout de bout en bout dans Jaeger, montrant le span Kafka publish orders.

🔍 Comment l’afficher sans dérouler 48 spans : dans la barre Find en haut de la trace, tapez kafka, puis cliquez sur l’icône cible ⌖ juste à droite du champ (entre le ? et les flèches). Jaeger masque tout le reste et ouvre les résultats, détails dépliés. Cliquez à nouveau sur la cible pour revenir à la trace entière.

kafka remonte deux résultats, et c’est normal : le champ Find ne cherche pas que dans les noms d’opération, il fouille aussi les attributs et les events de chaque span. Le second résultat est le span oteldemo.CheckoutService/PlaceOrder, qui contient un event d’évaluation du feature flag kafkaQueueProblems — un des interrupteurs de panne de la démo. Cherchez publish orders si vous voulez atterrir directement sur le bon span.