O kit do labo — https://github.com/hrhouma2/aiopsatlas-observabilite-labo-fr — clonado em
lab3na lição 03. Todos os comandos desta lição são digitados a partir dessa pasta. O Grafana é descrito na porta 3000; se você escolheuGRAFANA_PORT=3001, substitua 3000 por 3001 em todo lugar.
Iniciar o labo é como girar a chave: o motor (Docker) liga os dez serviços, os contadores se acendem um por um, e depois de um minuto o painel de controle está vivo. As nove interfaces web são os nove mostradores desse painel: cada uma mostra o mesmo labo por um ângulo diferente. O Prometheus é o contador bruto; o Grafana é o para-brisa, a visão confortável sobre os mesmos números; Alertmanager e o webhook são os avisos luminosos; a API é a estrada que o carro está percorrendo.
demarrer encadeia quatro fases. Ele baixa as seis imagens públicas (Prometheus, Alertmanager, Grafana, Alloy, node-exporter, cAdvisor: cerca de 1,5 GB na primeira vez, nada depois); ele constrói as quatro imagens locais (api, charge, webhook a partir de python:3.13-slim, e loki para adicionar a ela um binário busybox usado no teste de saúde); ele cria uma rede Docker (labo-observabilite_labo) e três volumes (grafana-data, prometheus-data, loki-data); depois ele inicia os dez contêineres e espera que cada um responda ao seu teste de saúde (healthcheck). Alguns serviços dependem de outros: charge só inicia depois que a API estiver saudável, grafana e alloy esperam o Prometheus e o Loki.
Os três volumes são a memória do labo. arreter para os contêineres, mas mantém os volumes: as séries do Prometheus, os logs do Loki e as configurações do Grafana sobrevivem, e demarrer retoma de onde você estava. reinitialiser apaga os volumes: labo novo. Documentação: Docker Compose — Volumes e Docker Compose — Healthchecks et depends_on.
| Comando | O que faz | Quando usar |
|---|---|---|
prerequis | Verifica Docker, Compose, memória, processadores, as nove portas | Antes do primeiro demarrer (lição 03) |
demarrer | Baixa, constrói, cria rede e volumes, inicia os 10 serviços, espera que fiquem prontos | No início de cada sessão |
etat | Tabela dos contêineres, targets do Prometheus, séries, alertas, estado de cada interface | Sempre: é seu primeiro reflexo |
journal <service> | As 100 últimas linhas de log de um serviço | Quando um serviço não responde, ou para ler os logs da API |
casser <scenario> | Provoca uma falha: api, erreurs, lenteur, disque | Prática deste módulo e dos módulos seguintes |
reparer | Cancela todas as falhas | Depois de cada casser |
arreter | Para os contêineres, mantém os dados | No fim da sessão |
reinitialiser | Remove contêineres e volumes, depois de confirmação | Para começar do zero |
As nove interfaces, e o que se observa em cada uma:
| Interface | URL | O que você observa |
|---|---|---|
| Prometheus | http://localhost:9090 | A página Query para digitar uma query, Alerts para as regras, Status → Target health para os 8 targets |
| Alertmanager | http://localhost:9093 | Os alertas recebidos, agrupados por alertname e service; os silêncios |
| Grafana | http://localhost:3000 | Os três painéis de controle provisionados, Explore, as três fontes de dados |
| API catálogo | http://localhost:8000 | /cours, /cours/C0001, /sante, /metrics: o serviço observado, visto de fora |
| webhook | http://localhost:8090 | A lista de alertas recebidos do Alertmanager, atualizada a cada 10 s |
| Loki | http://localhost:3100/ready | Responde ready; o Loki não tem interface, é consultado via Grafana |
| Alloy | http://localhost:12345 | Sua interface de diagnóstico: os componentes de config.alloy e seu estado |
| node-exporter | http://localhost:9100/metrics | A página bruta de métricas da máquina hospedeira |
| cAdvisor | http://localhost:8080 | As métricas por contêiner; /metrics para a página bruta |
Iniciar. A partir de lab3:
.\labo.ps1 demarrer./labo.sh demarrerNa máquina do curso, na primeira inicialização (as linhas de download e construção foram cortadas):
== 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)O que é preciso ver: os quatro Skipped Image can be built (as imagens locais não são baixadas, são construídas), os três volumes criados, labo-charge Starting só depois de labo-api Healthy, depois os dez prêt. Na máquina do curso, demarrer levou 44 segundos com as imagens já em cache. A última linha diz para esperar dois minutos: o Prometheus precisa de alguns scrapes para desenhar uma curva.
Ler 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.O que é preciso ver: dois blocos. Conteneurs: dez linhas, todas Up … (healthy). Supervision: o Prometheus lê seus 8 targets, armazena 9038 séries (esse número sobe nos primeiros minutos, depois se estabiliza em torno de 12.000 a 15.000 na máquina do curso), nenhum alerta; a API conhece 64 cursos; o webhook não recebeu nada. A última linha, Labo : 10/10 services, 8/8 cibles up, 0 alertes actives., é a que você deve reencontrar ao final de cada prática.
Prometheus: Query, Alerts, Status. Abra http://localhost:9090. O menu do topo tem três entradas: Query, Alerts, Status. Em Status, o submenu oferece Target health, Rule health, Service discovery, Runtime & build information, TSDB status, Command-line flags, Configuration, Alertmanager discovery. Vá em Target health: oito blocos, um por job, cada um com 1 / 1 up, a URL lida (Endpoint), os labels, a data do último scrape e o estado UP. Na máquina do curso:
api
1 / 1 up
Endpoint Labels Last scrape State
http://api:8000/metrics instance="api:8000" job="api" service="api" 6.014s ago UPVolte para Query, digite up no campo de entrada e clique em Execute (ou Enter). Sob o campo, três abas: Table, Graph, Explain. Em Table, oito linhas do tipo up{instance="localhost:9090", job="prometheus"} 1, todas em 1. Sob as abas, uma linha do tipo Load time: 40ms Result series: 8 diz quantas séries responderam. Passe para Graph: oito linhas planas em 1. O módulo 2 vai passar o resto do tempo nessa página.
Grafana: três painéis de controle prontos. Abra http://localhost:3000, usuário admin, senha aiopsatlas2026. A página inicial lista Recent dashboards: os três painéis de controle provisionados pelo kit, na pasta Labo observabilite. O menu principal (ícone no topo à esquerda) oferece Dashboards, Explore, Alerting, Connections → Data sources. Em Connections → Data sources, três fontes: Prometheus (padrão), Loki, Alertmanager. A API do Grafana confirma a mesma lista:
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=FalseAbra API catalogue — signaux dorés: os quatro sinais de ouro (tráfego, erros, latência, saturação) da API, mais duas métricas de negócio (inscrições, cursos consultados). As curvas estão planas no início: é preciso dois minutos de carga. O que é preciso ver: nada do que você vê aqui é armazenado no Grafana. Cada painel envia uma query PromQL para o Prometheus no momento em que você olha. O Grafana é o para-brisa, não o motor.
O Loki se lê no mesmo lugar. Abra Explore no menu, escolha a fonte Loki no seletor no topo, digite {service="api"} no campo de query e execute com Run query: as linhas JSON da API rolam, as mais recentes no topo, cada uma com seus labels. O Loki só conhece quatro neste labo, obtidos por http://localhost:3100/loki/api/v1/labels: code, conteneur, niveau, service. service e conteneur vêm do Docker, niveau e code são extraídos do JSON pelo Alloy. Alterne o seletor para Prometheus, digite up, Run query: as oito séries da etapa 3 aparecem, em tabela e em curva. O Explore é o lugar onde se testa uma query antes de fazer um painel dela (lição 07).
A API de catálogo, de fora. Abra as quatro URLs seguintes no navegador, ou com 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 02O que é preciso ver: /sante é a rota que o Docker chama para o healthcheck; /cours/C0001 é um dos 64 cursos; /cours/C9999 responde um 404 limpo, que a API conta em http_requetes_total{code="404",route="/cours/{id}"} e escreve em um log WARNING; /metrics é o que o Prometheus lê. Cada resposta traz um cabeçalho x-id-requete (por exemplo c5c49525ea53), o mesmo identificador que aparece no log JSON dessa requisição.
Alertmanager e o webhook: os avisos luminosos, apagados. Abra http://localhost:9093: o menu oferece Alerts, Silences, Status, Settings, e um botão New Silence. Em funcionamento normal, a página Alerts está vazia. Abra http://localhost:8090: uma página "Alertes reçues d'Alertmanager" com uma tabela de seis colunas (Reçue à, Alerte, Sévérité, État, Service, Résumé) e a linha Aucune alerte reçue pour l'instant.; a página se atualiza a cada 10 segundos. O formato bruto está em http://localhost:8090/alertes.json ([]) e o estado do serviço em http://localhost:8090/sante:
{"etat":"ok","alertes_en_memoire":0,"notifications":0,"alertes":0}O que é preciso ver: duas páginas vazias, e é isso que se quer. A prática deste módulo as preenche com casser api.
Loki, Alloy, node-exporter, cAdvisor: os bastidores. Quatro páginas sem interface amigável:
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"}…)O que é preciso ver: o Loki e o Alloy respondem em uma palavra; eles trabalham para o Grafana, não diretamente para você. Os dois exporters expõem o mesmo formato de página que a API (# HELP, # TYPE, uma linha por série), com muito mais linhas. Abra http://localhost:8080 sem /metrics: o cAdvisor redireciona para /containers/, uma pequena página que mostra a máquina inteira (Usage Overview, CPU Total Usage, Memory Total Usage, Network Throughput) e um link Docker Containers para o detalhe de cada contêiner.
Ler um log.
.\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"}Depois 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}}O que é preciso ver: a API escreve uma linha por requisição; o gerador de carga escreve um resumo a cada 30 segundos, cerca de 260 requisições (quase 9 por segundo), das quais uma vintena de 404 e alguns 500 propositais. Esses números são os que você vai reencontrar no Prometheus com rate() no módulo 2.
Parar, depois reiniciar sem perder nada.
.\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 então mostra dez linhas Exited; etat termina com Labo : 0/10 services, ?/? cibles up, ? alertes actives. (os ? porque o Prometheus não responde mais). Execute novamente .\labo.ps1 demarrer: dessa vez, sem download, sem construção, cerca de trinta segundos. No Prometheus, digite up e passe para Graph com um período de uma hora: a curva se interrompe durante a parada e retoma, com o histórico anterior intacto. É o volume prometheus-data que manteve as séries.
demarrer para em um serviço. A mensagem é explícita: Un service n'a pas démarré. Regardez son journal : .\labo.ps1 journal <service>. Faça isso. O caso mais frequente é uma porta ocupada entre prerequis e demarrer (outro programa iniciado nesse meio-tempo): o Docker então recusa publicar a porta, e o log do contêiner está vazio porque ele nunca iniciou. Execute prerequis novamente.
journal sem nome de serviço. .\labo.ps1 journal sozinho exibe:
usage : .\labo.ps1 journal <prometheus|alertmanager|loki|alloy|node-exporter|cadvisor|api|webhook|charge|grafana>Os dez nomes válidos estão ali; são os nomes dos serviços em docker-compose.yml, não os dos contêineres (api, não labo-api). Da mesma forma, .\labo.ps1 casser tout responde usage : .\labo.ps1 casser <api|erreurs|lenteur|disque>.
O Grafana responde Unauthorized. Se você chamar a API do Grafana sem estar conectado, por exemplo http://localhost:3000/api/search em uma aba privada, você recebe:
{"extra":null,"message":"Unauthorized","messageId":"auth.unauthorized","statusCode":401,"traceID":""}Isso é normal: as páginas de API exigem uma sessão ou uma senha. Conecte-se primeiro em http://localhost:3000 (admin / aiopsatlas2026), depois recarregue.
Os painéis de controle do Grafana exibem "No data". Duas causas, nesta ordem: o labo está rodando há menos de dois minutos (espere); ou o período no topo direito aponta para um período em que o labo estava parado (coloque de volta "Last 15 minutes" ou "Last 1 hour").
etat exibe Labo : 0/10 services, ?/? cibles up, ? alertes actives. O labo está parado. .\labo.ps1 demarrer.
No PowerShell, demarrer exibe linhas vermelhas NativeCommandError em torno de Container labo-api Stopping. São as mensagens de progresso do Docker Compose, escritas na saída de erro; quando labo.ps1 é ele mesmo executado a partir de outro script ou com 2>&1, o PowerShell 5.1 as apresenta como erro. O labo iniciou normalmente: verifique com etat.
demarrer baixa seis imagens, constrói quatro imagens locais, cria uma rede e três volumes, depois inicia dez contêineres e espera seus testes de saúde; 44 segundos na máquina do curso com as imagens já em cache. etat tem dois blocos: os contêineres (dez Up … (healthy)) e a supervisão (8/8 targets, o número de séries, os alertas, o estado de cada interface); sua última linha nominal é Labo : 10/10 services, 8/8 cibles up, 0 alertes actives.. O Prometheus (9090) tem três páginas: Query com suas abas Table, Graph, Explain; Alerts; Status → Target health com os 8 targets UP. O Grafana (3000, admin / aiopsatlas2026) tem três painéis de controle provisionados na pasta Labo observabilite e três fontes de dados, Prometheus por padrão; ele não armazena nenhuma medida ele mesmo. A API (8000) responde em /sante, /cours/C0001, /metrics, e um 404 limpo em um curso desconhecido, com um cabeçalho x-id-requete em cada resposta. Alertmanager (9093) e o webhook (8090) estão vazios em funcionamento normal. journal <service> recebe o nome do serviço, não do contêiner. arreter mantém os volumes: as séries sobrevivem, a curva up se interrompe e retoma.
grafana/provisioning/. É por isso que a pasta Labo observabilite aparece marcada "managed by classic file provisioning" na API.docker compose ps, logs, stop: os comandos que labo.ps1 e labo.sh encadeiam para você; journal api é docker compose logs --tail 100 api.etat, em Target health, no Alertmanager e no webhook, antes de reparar.