Start the lab and tour the interfaces

13 min
Audience
beginner, lesson 03 done (prerequis all green)
Duration
45 to 60 min (including 5 to 10 min of download the first time)
Module
1/7
Target skill
start the ten services with a single command, read the output of demarrer then of etat, open each of the nine lab interfaces knowing what to look at, read a log, stop and restart without losing data

The lab kithttps://github.com/hrhouma2/aiopsatlas-observabilite-labo-fr — cloned into lab3 in lesson 03. Every command in this lesson is typed from that folder. Grafana is described on port 3000; if you chose GRAFANA_PORT=3001, replace 3000 with 3001 everywhere.

In one image

Starting the lab is turning the key: the engine (Docker) launches the ten services, the gauges light up one by one, and after a minute the dashboard is alive. The nine web interfaces are the nine dials of that dashboard: each shows the same lab from a different angle. Prometheus is the raw meter; Grafana is the windshield, the comfortable view of the same numbers; Alertmanager and the webhook are the warning lights; the API is the road the car is driving on.

How it works

demarrer chains four phases. It downloads the six public images (Prometheus, Alertmanager, Grafana, Alloy, node-exporter, cAdvisor: about 1.5 GB the first time, nothing afterwards); it builds the four local images (api, charge, webhook from python:3.13-slim, and loki to add a busybox binary used by the health check); it creates a Docker network (labo-observabilite_labo) and three volumes (grafana-data, prometheus-data, loki-data); then it starts the ten containers and waits for each one to answer its health check (healthcheck). Some services depend on others: charge only starts once the API is healthy, grafana and alloy wait for Prometheus and Loki.

The three volumes are the lab's memory. arreter stops the containers but keeps the volumes: Prometheus series, Loki logs and Grafana settings survive, and demarrer resumes where you were. reinitialiser deletes the volumes: a brand-new lab. Documentation: Docker Compose — Volumes and Docker Compose — Healthchecks and depends_on.

CommandWhat it doesWhen to use it
prerequisChecks Docker, Compose, memory, processors, the nine portsBefore the first demarrer (lesson 03)
demarrerDownloads, builds, creates network and volumes, starts the 10 services, waits until they are readyAt the start of each session
etatTable of containers, Prometheus targets, series, alerts, state of each interfaceAll the time: it is your first reflex
journal <service>The last 100 log lines of a serviceWhen a service does not answer, or to read the API logs
casser <scenario>Triggers an outage: api, erreurs, lenteur, disquePractice of this module and following modules
reparerCancels every outageAfter each casser
arreterStops the containers, keeps the dataAt the end of a session
reinitialiserDeletes containers and volumes, after confirmationTo start from scratch

The nine interfaces, and what to look at there:

InterfaceURLWhat you look at
Prometheushttp://localhost:9090The Query page to type a query, Alerts for the rules, Status → Target health for the 8 targets
Alertmanagerhttp://localhost:9093The alerts received, grouped by alertname and service; the silences
Grafanahttp://localhost:3000The three provisioned dashboards, Explore, the three data sources
Catalog APIhttp://localhost:8000/cours, /cours/C0001, /sante, /metrics: the observed service, seen from the outside
webhookhttp://localhost:8090The list of alerts received from Alertmanager, refreshed every 10 s
Lokihttp://localhost:3100/readyAnswers ready; Loki has no interface, it is queried through Grafana
Alloyhttp://localhost:12345Its diagnostic interface: the components of config.alloy and their state
node-exporterhttp://localhost:9100/metricsThe raw metrics page of the host machine
cAdvisorhttp://localhost:8080The per-container metrics; /metrics for the raw page

Step by step

  1. Start. From lab3:

    powershell
    .\labo.ps1 demarrer
    bash
    ./labo.sh demarrer

    On the course machine, at first startup (download and build lines are cut):

    text
    
    == 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)

    What to see: the four Skipped Image can be built (local images are not downloaded, they are built), the three volumes created, labo-charge Starting only after labo-api Healthy, then the ten prêt (ready). On the course machine, demarrer took 44 seconds once the images were cached. The last line tells you to wait two minutes: Prometheus needs a few scrapes to draw a curve.

  2. Read etat.

    powershell
    .\labo.ps1 etat
    text
    
    == 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.

    What to see: two blocks. Conteneurs (containers): ten lines, all Up … (healthy). Supervision: Prometheus reads its 8 targets, stores 9038 series (this number climbs during the first minutes, then stabilizes around 12,000 to 15,000 on the course machine), no alert; the API knows 64 courses; the webhook received nothing. The last line, Labo : 10/10 services, 8/8 cibles up, 0 alertes actives., is the one you must find again at the end of every practice.

  3. Prometheus: Query, Alerts, Status. Open http://localhost:9090. The top menu has three entries: Query, Alerts, Status. Under Status, the submenu offers Target health, Rule health, Service discovery, Runtime & build information, TSDB status, Command-line flags, Configuration, Alertmanager discovery. Go to Target health: eight blocks, one per job, each with 1 / 1 up, the URL read (Endpoint), the labels, the date of the last scrape and the UP state. On the course machine:

    text
    api
    1 / 1 up
    Endpoint                    Labels                                   Last scrape   State
    http://api:8000/metrics     instance="api:8000" job="api" service="api"   6.014s ago    UP

    Go back to Query, type up in the input field and click Execute (or Enter). Under the field, three tabs: Table, Graph, Explain. In Table, eight lines of the form up{instance="localhost:9090", job="prometheus"} 1, all at 1. Under the tabs, a line such as Load time: 40ms Result series: 8 tells you how many series answered. Switch to Graph: eight flat lines at 1. Module 2 will spend the rest of its time on this page.

  4. Grafana: three ready-made dashboards. Open http://localhost:3000, user admin, password aiopsatlas2026. The home page lists Recent dashboards: the three dashboards provisioned by the kit, in the Labo observabilite folder. The main menu (icon at the top left) gives Dashboards, Explore, Alerting, Connections → Data sources. In Connections → Data sources, three sources: Prometheus (default), Loki, Alertmanager. Grafana's API confirms the same list:

    text
    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=False

    Open API catalogue — signaux dorés (catalog API — golden signals): the four golden signals (traffic, errors, latency, saturation) of the API, plus two business metrics (enrollments, courses viewed). The curves are flat at first: it takes two minutes of load. What to see: nothing you see here is stored in Grafana. Each panel sends a PromQL query to Prometheus at the moment you look. Grafana is the windshield, not the engine.

    Loki is read in the same place. Open Explore in the menu, choose the Loki source in the selector at the top, type {service="api"} in the query field and run it with Run query: the API's JSON lines scroll by, most recent first, each with its labels. Loki knows only four labels on this lab, obtained from http://localhost:3100/loki/api/v1/labels: code, conteneur, niveau, service. service and conteneur come from Docker, niveau and code are extracted from the JSON by Alloy. Switch the selector to Prometheus, type up, Run query: the eight series from step 3 appear, as a table and as a curve. Explore is where you try a query before turning it into a panel (lesson 07).

  5. The catalog API, from the outside. Open the following four URLs in the browser, or with Invoke-RestMethod / curl:

    text
    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 02

    What to see: /sante is the route Docker calls for the healthcheck; /cours/C0001 is one of the 64 courses; /cours/C9999 returns a clean 404, which the API counts in http_requetes_total{code="404",route="/cours/{id}"} and writes to a WARNING log; /metrics is what Prometheus reads. Each response carries an x-id-requete header (for example c5c49525ea53), the same identifier as in the JSON log of that request.

  6. Alertmanager and the webhook: the warning lights, off. Open http://localhost:9093: the menu offers Alerts, Silences, Status, Settings, and a New Silence button. In normal operation, the Alerts page is empty. Open http://localhost:8090: a page « Alertes reçues d'Alertmanager » (alerts received from Alertmanager) with a six-column table (Reçue à, Alerte, Sévérité, État, Service, Résumé — received at, alert, severity, state, service, summary) and the line Aucune alerte reçue pour l'instant. (no alert received yet); the page refreshes every 10 seconds. The raw format is at http://localhost:8090/alertes.json ([]) and the service state at http://localhost:8090/sante:

    json
    {"etat":"ok","alertes_en_memoire":0,"notifications":0,"alertes":0}

    What to see: two empty pages, and that is what we want. This module's practice fills them with casser api.

  7. Loki, Alloy, node-exporter, cAdvisor: behind the scenes. Four pages without a comfortable interface:

    text
    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"}…)

    What to see: Loki and Alloy answer in one word; they work for Grafana, not for you directly. The two exporters expose the same page shape as the API (# HELP, # TYPE, one line per series), with many more lines. Open http://localhost:8080 without /metrics: cAdvisor redirects to /containers/, a small page showing the whole machine (Usage Overview, CPU Total Usage, Memory Total Usage, Network Throughput) and a Docker Containers link to the detail of each container.

  8. Read a log.

    powershell
    .\labo.ps1 journal api
    text
    labo-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"}

    Then journal charge:

    text
    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}}

    What to see: the API writes one line per request; the load generator writes a summary every 30 seconds, about 260 requests (nearly 9 per second), including some twenty 404s and a few deliberate 500s. These numbers are the ones you will find again in Prometheus with rate() in module 2.

  9. Stop, then restart without losing anything.

    powershell
    .\labo.ps1 arreter
    text
     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 reprendre

    docker compose ps -a then shows ten Exited lines; etat ends with Labo : 0/10 services, ?/? cibles up, ? alertes actives. (the ? because Prometheus no longer answers). Run .\labo.ps1 demarrer again: this time, no download, no build, about thirty seconds. In Prometheus, type up and switch to Graph with a one-hour range: the curve stops during the shutdown and resumes, with the earlier history intact. The prometheus-data volume kept the series.

If it breaks

  • demarrer stops on a service. The message is explicit: Un service n'a pas démarré. Regardez son journal : .\labo.ps1 journal <service> (a service did not start, look at its log). Do it. The most frequent case is a port taken between prerequis and demarrer (another program launched in between): Docker then refuses to publish the port, and the container's log is empty because it never started. Run prerequis again.

  • journal without a service name. .\labo.ps1 journal alone displays:

    text
    usage : .\labo.ps1 journal <prometheus|alertmanager|loki|alloy|node-exporter|cadvisor|api|webhook|charge|grafana>

    The ten valid names are there; they are the service names in docker-compose.yml, not the container names (api, not labo-api). Likewise, .\labo.ps1 casser tout answers usage : .\labo.ps1 casser <api|erreurs|lenteur|disque>.

  • Grafana answers Unauthorized. If you call Grafana's API without being logged in, for example http://localhost:3000/api/search in a private tab, you get:

    json
    {"extra":null,"message":"Unauthorized","messageId":"auth.unauthorized","statusCode":401,"traceID":""}

    This is normal: API pages require a session or a password. Log in first at http://localhost:3000 (admin / aiopsatlas2026), then reload.

  • Grafana dashboards display "No data". Two causes, in this order: the lab has been running for less than two minutes (wait); or the time range at the top right points to a period when the lab was stopped (set it back to "Last 15 minutes" or "Last 1 hour").

  • etat displays Labo : 0/10 services, ?/? cibles up, ? alertes actives. The lab is stopped. .\labo.ps1 demarrer.

  • Under PowerShell, demarrer displays red NativeCommandError lines around Container labo-api Stopping. These are Docker Compose's progress messages, written to the error output; when labo.ps1 is itself launched from another script or with 2>&1, PowerShell 5.1 dresses them up as errors. The lab did start: check with etat.

To remember

demarrer downloads six images, builds four local images, creates a network and three volumes, then launches ten containers and waits for their health checks; 44 seconds on the course machine once the images are cached. etat has two blocks: the containers (ten Up … (healthy)) and the supervision (8/8 targets, the number of series, the alerts, the state of each interface); its nominal last line is Labo : 10/10 services, 8/8 cibles up, 0 alertes actives.. Prometheus (9090) has three pages: Query with its Table, Graph, Explain tabs; Alerts; Status → Target health with the 8 UP targets. Grafana (3000, admin / aiopsatlas2026) has three dashboards provisioned in the Labo observabilite folder and three data sources, Prometheus by default; it stores no measurement itself. The API (8000) answers on /sante, /cours/C0001, /metrics, and a clean 404 on an unknown course, with an x-id-requete header on every response. Alertmanager (9093) and the webhook (8090) are empty in normal operation. journal <service> takes the service name, not the container name. arreter keeps the volumes: the series survive, the up curve stops then resumes.

To go further

  • Prometheus — Expression browser: the Query page, its tabs and options, in the official documentation.
  • Grafana — Provisioning: how the three dashboards and the three data sources arrive in Grafana at startup, through the files in grafana/provisioning/. This is why the Labo observabilite folder is marked "managed by classic file provisioning" in the API.
  • Grafana Alloy — Debugging UI: what http://localhost:12345 shows, component by component.
  • Docker Compose — docker compose ps, logs, stop: the commands that labo.ps1 and labo.sh chain for you; journal api is docker compose logs --tail 100 api.
  • The guided practice that follows redoes this tour in one go, then breaks the API to watch the warning light come on, in etat, in Target health, in Alertmanager and in the webhook, before fixing it.