Le kit du labo — https://github.com/hrhouma2/aiopsatlas-observabilite-labo-fr — cloné dans
lab3à la leçon 03. Toutes les commandes de cette leçon se tapent depuis ce dossier. Grafana est décrit sur le port 3000 ; si tu as choisiGRAFANA_PORT=3001, remplace 3000 par 3001 partout.
Démarrer le labo, c'est tourner la clé : le moteur (Docker) lance les dix services, les compteurs s'allument un par un, et au bout d'une minute le tableau de bord est vivant. Les neuf interfaces web sont les neuf cadrans de ce tableau de bord : chacune montre le même labo sous un angle différent. Prometheus est le compteur brut ; Grafana est le pare-brise, la vue confortable sur les mêmes chiffres ; Alertmanager et le webhook sont les voyants ; l'API est la route que la voiture est en train de parcourir.
demarrer enchaîne quatre phases. Il télécharge les six images publiques (Prometheus, Alertmanager, Grafana, Alloy, node-exporter, cAdvisor : environ 1,5 Go la première fois, rien ensuite) ; il construit les quatre images locales (api, charge, webhook depuis python:3.13-slim, et loki pour lui ajouter un binaire busybox qui sert au test de santé) ; il crée un réseau Docker (labo-observabilite_labo) et trois volumes (grafana-data, prometheus-data, loki-data) ; puis il démarre les dix conteneurs et attend que chacun réponde à son test de santé (healthcheck). Certains services dépendent d'autres : charge ne démarre qu'une fois l'API saine, grafana et alloy attendent Prometheus et Loki.
Les trois volumes sont la mémoire du labo. arreter stoppe les conteneurs mais garde les volumes : les séries de Prometheus, les logs de Loki et les réglages de Grafana survivent, et demarrer reprend là où tu étais. reinitialiser supprime les volumes : labo neuf. Documentation : Docker Compose — Volumes et Docker Compose — Healthchecks et depends_on.
| Commande | Ce qu'elle fait | Quand l'utiliser |
|---|---|---|
prerequis | Vérifie Docker, Compose, la mémoire, les processeurs, les neuf ports | Avant le premier demarrer (leçon 03) |
demarrer | Télécharge, construit, crée réseau et volumes, démarre les 10 services, attend qu'ils soient prêts | Au début de chaque session |
etat | Tableau des conteneurs, cibles Prometheus, séries, alertes, état de chaque interface | Tout le temps : c'est ton premier réflexe |
journal <service> | Les 100 dernières lignes de journal d'un service | Quand un service ne répond pas, ou pour lire les logs de l'API |
casser <scenario> | Provoque une panne : api, erreurs, lenteur, disque | Pratique de ce module et modules suivants |
reparer | Annule toutes les pannes | Après chaque casser |
arreter | Arrête les conteneurs, garde les données | En fin de session |
reinitialiser | Supprime conteneurs et volumes, après confirmation | Pour repartir de zéro |
Les neuf interfaces, et ce qu'on y regarde :
| Interface | URL | Ce que tu y regardes |
|---|---|---|
| Prometheus | http://localhost:9090 | La page Query pour taper une requête, Alerts pour les règles, Status → Target health pour les 8 cibles |
| Alertmanager | http://localhost:9093 | Les alertes reçues, groupées par alertname et service ; les silences |
| Grafana | http://localhost:3000 | Les trois tableaux de bord provisionnés, Explore, les trois sources de données |
| API catalogue | http://localhost:8000 | /cours, /cours/C0001, /sante, /metrics : le service observé, vu de l'extérieur |
| webhook | http://localhost:8090 | La liste des alertes reçues d'Alertmanager, rafraîchie toutes les 10 s |
| Loki | http://localhost:3100/ready | Répond ready ; Loki n'a pas d'interface, on l'interroge via Grafana |
| Alloy | http://localhost:12345 | Son interface de diagnostic : les composants de config.alloy et leur état |
| node-exporter | http://localhost:9100/metrics | La page brute des métriques de la machine hôte |
| cAdvisor | http://localhost:8080 | Les métriques par conteneur ; /metrics pour la page brute |
Démarrer. Depuis lab3 :
.\labo.ps1 demarrer./labo.sh demarrerSur la machine du cours, au premier démarrage (les lignes de téléchargement et de construction sont coupées) :
== Téléchargement des images (long la première fois : ~1,5 Go) ==
Image labo-webhook:1.0.0 Skipped Image can be built
Image labo-api:1.0.0 Skipped Image can be built
Image labo-charge:1.0.0 Skipped Image can be built
Image labo-loki:3.7.7 Skipped Image can be built
…
== Construction des images du labo (api, charge, webhook, loki) et démarrage ==
…
Network labo-observabilite_labo Created
Volume labo-observabilite_grafana-data Created
Volume labo-observabilite_prometheus-data Created
Volume labo-observabilite_loki-data Created
…
Container labo-prometheus Healthy
Container labo-api Healthy
Container labo-charge Starting
Container labo-charge Started
Container labo-loki Healthy
Container labo-alloy Started
Container labo-grafana Started
== Attente que chaque service soit prêt ==
prometheus prêt (0 s)
alertmanager prêt (0 s)
loki prêt (0 s)
alloy .. prêt (6 s)
node-exporter prêt (0 s)
cadvisor prêt (0 s)
api prêt (0 s)
webhook prêt (0 s)
charge prêt (0 s)
grafana ... prêt (9 s)
Le labo est prêt.
Grafana http://localhost:3000 (utilisateur admin · mot de passe aiopsatlas2026)
Prometheus http://localhost:9090 (Status → Target health, puis onglet Graph)
Alertmanager http://localhost:9093
API catalogue http://localhost:8000/cours · http://localhost:8000/metrics
Webhook http://localhost:8090 (les alertes reçues)
Loki http://localhost:3100/ready · Alloy http://localhost:12345
node-exporter http://localhost:9100/metrics · cAdvisor http://localhost:8080
Étape suivante : .\labo.ps1 etat (laissez tourner 2 minutes pour avoir des courbes)Ce qu'il faut voir : les quatre Skipped Image can be built (les images locales ne se téléchargent pas, elles se construisent), les trois volumes créés, labo-charge Starting seulement après labo-api Healthy, puis les dix prêt. Sur la machine du cours, demarrer a pris 44 secondes une fois les images en cache. La dernière ligne te dit d'attendre deux minutes : Prometheus a besoin de quelques scrapes pour dessiner une courbe.
Lire etat.
.\labo.ps1 etat
== Conteneurs ==
NAME SERVICE STATUS
labo-alertmanager alertmanager Up About a minute (healthy)
labo-alloy alloy Up 48 seconds (healthy)
labo-api api Up About a minute (healthy)
labo-cadvisor cadvisor Up About a minute (healthy)
labo-charge charge Up About a minute (healthy)
labo-grafana grafana Up 48 seconds (healthy)
labo-loki loki Up About a minute (healthy)
labo-node-exporter node-exporter Up About a minute (healthy)
labo-prometheus prometheus Up About a minute (healthy)
labo-webhook webhook Up About a minute (healthy)
== Supervision ==
✔ Prometheus répond — cibles up : 8/8
séries en mémoire : 9038
alertes : 0 active(s), 0 en attente (pending)
✔ Alertmanager répond (http://localhost:9093)
✔ Grafana répond (http://localhost:3000)
✔ Loki répond (http://localhost:3100)
✔ API catalogue répond — version 1.0.0, 64 cours
✔ Webhook répond — 0 alerte(s) reçue(s) (http://localhost:8090)
Labo : 10/10 services, 8/8 cibles up, 0 alertes actives.Ce qu'il faut voir : deux blocs. Conteneurs : dix lignes, toutes Up … (healthy). Supervision : Prometheus lit ses 8 cibles, stocke 9038 séries (ce nombre monte pendant les premières minutes, puis se stabilise vers 12 000 à 15 000 sur la machine du cours), aucune alerte ; l'API connaît 64 cours ; le webhook n'a rien reçu. La dernière ligne, Labo : 10/10 services, 8/8 cibles up, 0 alertes actives., est celle que tu dois retrouver à la fin de chaque pratique.
Prometheus : Query, Alerts, Status. Ouvre http://localhost:9090. Le menu du haut a trois entrées : Query, Alerts, Status. Dans Status, le sous-menu propose Target health, Rule health, Service discovery, Runtime & build information, TSDB status, Command-line flags, Configuration, Alertmanager discovery. Va dans Target health : huit blocs, un par job, chacun avec 1 / 1 up, l'URL lue (Endpoint), les labels, la date du dernier scrape et l'état UP. Sur la machine du cours :
api
1 / 1 up
Endpoint Labels Last scrape State
http://api:8000/metrics instance="api:8000" job="api" service="api" 6.014s ago UPReviens sur Query, tape up dans le champ de saisie et clique Execute (ou Entrée). Sous le champ, trois onglets : Table, Graph, Explain. Dans Table, huit lignes de la forme up{instance="localhost:9090", job="prometheus"} 1, toutes à 1. Sous les onglets, une ligne du type Load time: 40ms Result series: 8 te dit combien de séries ont répondu. Passe sur Graph : huit lignes plates à 1. Le module 2 passera le reste du temps sur cette page.
Grafana : trois tableaux de bord prêts. Ouvre http://localhost:3000, utilisateur admin, mot de passe aiopsatlas2026. La page d'accueil liste Recent dashboards : les trois tableaux de bord provisionnés par le kit, dans le dossier Labo observabilite. Le menu principal (icône en haut à gauche) donne Dashboards, Explore, Alerting, Connections → Data sources. Dans Connections → Data sources, trois sources : Prometheus (par défaut), Loki, Alertmanager. L'API de Grafana confirme la même liste :
uid=api-catalogue titre=« API catalogue — signaux dorés » panneaux=23 dossier=Labo observabilite
uid=hote-conteneurs titre=« Hôte et conteneurs » panneaux=16 dossier=Labo observabilite
uid=journaux-api titre=« Journaux de l'API » panneaux=6 dossier=Labo observabilite
source Prometheus type=prometheus uid=prometheus default=True
source Loki type=loki uid=loki default=False
source Alertmanager type=alertmanager uid=alertmanager default=FalseOuvre API catalogue — signaux dorés : les quatre signaux dorés (trafic, erreurs, latence, saturation) de l'API, plus deux métriques métier (inscriptions, cours consultés). Les courbes sont plates au début : il faut deux minutes de charge. Ce qu'il faut voir : rien de ce que tu vois ici n'est stocké dans Grafana. Chaque panneau envoie une requête PromQL à Prometheus au moment où tu regardes. Grafana est le pare-brise, pas le moteur.
Loki se lit au même endroit. Ouvre Explore dans le menu, choisis la source Loki dans le sélecteur en haut, tape {service="api"} dans le champ de requête et lance avec Run query : les lignes JSON de l'API défilent, les plus récentes en haut, chacune avec ses labels. Loki n'en connaît que quatre sur ce labo, obtenus par http://localhost:3100/loki/api/v1/labels : code, conteneur, niveau, service. service et conteneur viennent de Docker, niveau et code sont extraits du JSON par Alloy. Bascule le sélecteur sur Prometheus, tape up, Run query : les huit séries de l'étape 3 apparaissent, en tableau et en courbe. Explore est l'endroit où l'on essaie une requête avant d'en faire un panneau (leçon 07).
L'API catalogue, de l'extérieur. Ouvre les quatre URL suivantes dans le navigateur, ou avec Invoke-RestMethod / curl :
http://localhost:8000/sante → {"etat":"ok","version":"1.0.0","cours":64}
http://localhost:8000/cours/C0001 → {"id":"C0001","titre":"Introduction à Python","categorie":"programmation","niveau":"debutant","prix":89,"duree_heures":6,"professeur":"Karim Haddad","tags":["code","algorithmes"],"note":4.8,"inscrits":2319}
http://localhost:8000/cours/C9999 → 404 {"detail":"cours C9999 introuvable"}
http://localhost:8000/metrics → 271 lignes de texte, les métriques de la leçon 02Ce qu'il faut voir : /sante est la route que Docker appelle pour le healthcheck ; /cours/C0001 est un des 64 cours ; /cours/C9999 répond un 404 propre, que l'API compte dans http_requetes_total{code="404",route="/cours/{id}"} et écrit dans un log WARNING ; /metrics est ce que Prometheus lit. Chaque réponse porte un en-tête x-id-requete (par exemple c5c49525ea53), le même identifiant que dans le log JSON de cette requête.
Alertmanager et le webhook : les voyants, éteints. Ouvre http://localhost:9093 : le menu propose Alerts, Silences, Status, Settings, et un bouton New Silence. En fonctionnement normal, la page Alerts est vide. Ouvre http://localhost:8090 : une page « Alertes reçues d'Alertmanager » avec un tableau à six colonnes (Reçue à, Alerte, Sévérité, État, Service, Résumé) et la ligne Aucune alerte reçue pour l'instant. ; la page se rafraîchit toutes les 10 secondes. Le format brut est sur http://localhost:8090/alertes.json ([]) et l'état du service sur http://localhost:8090/sante :
{"etat":"ok","alertes_en_memoire":0,"notifications":0,"alertes":0}Ce qu'il faut voir : deux pages vides, et c'est ce qu'on veut. La pratique de ce module les remplit avec casser api.
Loki, Alloy, node-exporter, cAdvisor : les coulisses. Quatre pages sans interface de confort :
http://localhost:3100/ready → ready
http://localhost:12345/-/ready → Alloy is ready.
http://localhost:9100/metrics → 1578 lignes (node_cpu_seconds_total, node_memory_MemTotal_bytes…)
http://localhost:8080/metrics → 3444 lignes (container_memory_working_set_bytes{name="labo-api"}…)Ce qu'il faut voir : Loki et Alloy répondent en un mot ; ils travaillent pour Grafana, pas pour toi directement. Les deux exporters exposent la même forme de page que l'API (# HELP, # TYPE, une ligne par série), avec beaucoup plus de lignes. Ouvre http://localhost:8080 sans /metrics : cAdvisor redirige vers /containers/, une petite page qui montre la machine entière (Usage Overview, CPU Total Usage, Memory Total Usage, Network Throughput) et un lien Docker Containers vers le détail de chaque conteneur.
Lire un journal.
.\labo.ps1 journal apilabo-api | {"horodatage": "2026-09-15T19:33:25.839+00:00", "niveau": "INFO", "id_requete": "46bb533b33e9", "methode": "GET", "route": "/cours/{id}", "code": 200, "duree_ms": 13.9, "message": "GET /cours/C0038 -> 200"}
labo-api | {"horodatage": "2026-09-15T19:33:25.843+00:00", "niveau": "INFO", "id_requete": "5c0d4e124807", "methode": "GET", "route": "/cours", "code": 200, "duree_ms": 30.4, "message": "GET /cours -> 200"}
labo-api | {"horodatage": "2026-09-15T19:33:25.916+00:00", "niveau": "INFO", "id_requete": "5ccaee4d1a2a", "methode": "GET", "route": "/sante", "code": 200, "duree_ms": 1.0, "message": "GET /sante -> 200"}Puis journal charge :
labo-charge | {"horodatage": "2026-09-15T19:33:22.848+00:00", "niveau": "INFO", "message": "résumé des 30 dernières secondes", "requetes": {"201": 28, "total": 264, "200": 210, "404": 21, "422": 2, "500": 3}}Ce qu'il faut voir : l'API écrit une ligne par requête ; le générateur de charge écrit un résumé toutes les 30 secondes, environ 260 requêtes (près de 9 par seconde), dont une vingtaine de 404 et quelques 500 volontaires. Ces chiffres sont ceux que tu retrouveras dans Prometheus avec rate() au module 2.
Arrêter, puis redémarrer sans rien perdre.
.\labo.ps1 arreter Container labo-webhook Stopping
Container labo-alertmanager Stopping
…
Container labo-api Stopped
Container labo-prometheus Stopped
✔ conteneurs arrêtés — vos données sont conservées ; .\labo.ps1 demarrer pour reprendredocker compose ps -a montre alors dix lignes Exited ; etat se termine par Labo : 0/10 services, ?/? cibles up, ? alertes actives. (les ? parce que Prometheus ne répond plus). Relance .\labo.ps1 demarrer : cette fois, pas de téléchargement, pas de construction, une trentaine de secondes. Dans Prometheus, tape up et passe sur Graph avec une plage d'une heure : la courbe s'interrompt pendant l'arrêt et reprend, avec l'historique d'avant intact. C'est le volume prometheus-data qui a gardé les séries.
demarrer s'arrête sur un service. Le message est explicite : Un service n'a pas démarré. Regardez son journal : .\labo.ps1 journal <service>. Fais-le. Le cas le plus fréquent est un port pris entre prerequis et demarrer (un autre programme lancé entre-temps) : Docker refuse alors de publier le port, et le journal du conteneur est vide parce qu'il n'a jamais démarré. Relance prerequis.
journal sans nom de service. .\labo.ps1 journal seul affiche :
usage : .\labo.ps1 journal <prometheus|alertmanager|loki|alloy|node-exporter|cadvisor|api|webhook|charge|grafana>Les dix noms valides sont là ; ce sont les noms des services dans docker-compose.yml, pas ceux des conteneurs (api, pas labo-api). De même, .\labo.ps1 casser tout répond usage : .\labo.ps1 casser <api|erreurs|lenteur|disque>.
Grafana répond Unauthorized. Si tu appelles l'API de Grafana sans être connecté, par exemple http://localhost:3000/api/search dans un onglet privé, tu obtiens :
{"extra":null,"message":"Unauthorized","messageId":"auth.unauthorized","statusCode":401,"traceID":""}C'est normal : les pages d'API demandent une session ou un mot de passe. Connecte-toi d'abord sur http://localhost:3000 (admin / aiopsatlas2026), puis recharge.
Les tableaux de bord Grafana affichent « No data ». Deux causes, dans cet ordre : le labo tourne depuis moins de deux minutes (attends) ; ou la plage de temps en haut à droite pointe sur une période où le labo était arrêté (remets « Last 15 minutes » ou « Last 1 hour »).
etat affiche Labo : 0/10 services, ?/? cibles up, ? alertes actives. Le labo est arrêté. .\labo.ps1 demarrer.
Sous PowerShell, demarrer affiche des lignes rouges NativeCommandError autour de Container labo-api Stopping. Ce sont les messages de progression de Docker Compose, écrits sur la sortie d'erreur ; quand labo.ps1 est lui-même lancé depuis un autre script ou avec 2>&1, PowerShell 5.1 les habille en erreur. Le labo a bien démarré : vérifie avec etat.
demarrer télécharge six images, construit quatre images locales, crée un réseau et trois volumes, puis lance dix conteneurs et attend leurs tests de santé ; 44 secondes sur la machine du cours une fois les images en cache. etat a deux blocs : les conteneurs (dix Up … (healthy)) et la supervision (8/8 cibles, le nombre de séries, les alertes, l'état de chaque interface) ; sa dernière ligne nominale est Labo : 10/10 services, 8/8 cibles up, 0 alertes actives.. Prometheus (9090) a trois pages : Query avec ses onglets Table, Graph, Explain ; Alerts ; Status → Target health avec les 8 cibles UP. Grafana (3000, admin / aiopsatlas2026) a trois tableaux de bord provisionnés dans le dossier Labo observabilite et trois sources de données, Prometheus par défaut ; il ne stocke aucune mesure lui-même. L'API (8000) répond sur /sante, /cours/C0001, /metrics, et un 404 propre sur un cours inconnu, avec un en-tête x-id-requete à chaque réponse. Alertmanager (9093) et le webhook (8090) sont vides en fonctionnement normal. journal <service> prend le nom du service, pas du conteneur. arreter garde les volumes : les séries survivent, la courbe up s'interrompt puis reprend.
grafana/provisioning/. C'est pourquoi le dossier Labo observabilite est marqué « managed by classic file provisioning » dans l'API.docker compose ps, logs, stop : les commandes que labo.ps1 et labo.sh enchaînent pour toi ; journal api est docker compose logs --tail 100 api.etat, dans Target health, dans Alertmanager et dans le webhook, avant de réparer.