حقيبة المختبر — https://github.com/hrhouma2/aiopsatlas-observabilite-labo-fr — مستنسخة في
lab3في الدرس 03. تُكتب جميع أوامر هذا الدرس من هذا المجلد. Grafana موصوف على المنفذ 3000 ؛ إذا اخترتGRAFANA_PORT=3001، استبدل 3000 بـ 3001 في كل مكان.
بدء تشغيل المختبر هو إدارة المفتاح : المحرك (Docker) يشغّل الخدمات العشر، وتضيء العدادات واحداً تلو الآخر، وبعد دقيقة تصبح لوحة القيادة حية. الواجهات التسع هي الأقراص التسعة في لوحة القيادة هذه : كل واحدة تعرض المختبر نفسه من زاوية مختلفة. Prometheus هو العداد الخام ؛ Grafana هو الزجاج الأمامي، الرؤية المريحة للأرقام نفسها ؛ Alertmanager وwebhook هما المصابيح التحذيرية ؛ API هو الطريق التي تقطعها السيارة الآن.
يتسلسل demarrer في أربع مراحل. يُنزّل الصور العامة الست (Prometheus وAlertmanager وGrafana وAlloy وnode-exporter وcAdvisor : حوالي 1,5 غيغابايت في المرة الأولى، ولا شيء بعدها) ؛ يبني الصور المحلية الأربع (api وcharge وwebhook انطلاقاً من python:3.13-slim، وloki لإضافة ملف ثنائي busybox إليه يُستخدم لفحص الصحة) ؛ ينشئ شبكة Docker (labo-observabilite_labo) وثلاثة مجلدات تخزين (grafana-data وprometheus-data وloki-data) ؛ ثم يبدأ تشغيل الحاويات العشر وينتظر أن تستجيب كل واحدة لفحص صحتها (healthcheck). بعض الخدمات تعتمد على أخرى : لا يبدأ charge إلا بعد أن يصبح API سليماً، وgrafana وalloy ينتظران Prometheus وLoki.
مجلدات التخزين الثلاثة هي ذاكرة المختبر. arreter يوقف الحاويات لكنه يحتفظ بمجلدات التخزين : سلاسل Prometheus وسجلات Loki وإعدادات Grafana تبقى، وdemarrer يستأنف من حيث كنت. reinitialiser يحذف مجلدات التخزين : مختبر جديد. التوثيق : Docker Compose — Volumes وDocker Compose — Healthchecks et depends_on.
| الأمر | ما يفعله | متى يُستخدم |
|---|---|---|
prerequis | يتحقق من Docker وCompose والذاكرة والمعالجات والمنافذ التسعة | قبل أول demarrer (الدرس 03) |
demarrer | يُنزّل ويبني وينشئ الشبكة ومجلدات التخزين ويبدأ الخدمات العشر وينتظر جاهزيتها | في بداية كل جلسة |
etat | جدول الحاويات وأهداف Prometheus والسلاسل والتنبيهات وحالة كل واجهة | طوال الوقت : إنه ردّ فعلك الأول |
journal <service> | آخر 100 سطر من سجل خدمة | عندما لا تستجيب خدمة، أو لقراءة سجلات API |
casser <scenario> | يستحضر عطلاً : api أو erreurs أو lenteur أو disque | تمرين هذه الوحدة والوحدات التالية |
reparer | يلغي جميع الأعطال | بعد كل casser |
arreter | يوقف الحاويات، ويحتفظ بالبيانات | في نهاية الجلسة |
reinitialiser | يحذف الحاويات ومجلدات التخزين، بعد التأكيد | للبدء من الصفر |
الواجهات التسع، وما ننظر إليه فيها :
| الواجهة | العنوان | ما تنظر إليه فيها |
|---|---|---|
| Prometheus | http://localhost:9090 | صفحة Query لكتابة استعلام، وAlerts للقواعد، وStatus → Target health للأهداف الثمانية |
| Alertmanager | http://localhost:9093 | التنبيهات المستلمة، مجمّعة حسب alertname وservice ؛ الإسكاتات |
| Grafana | http://localhost:3000 | لوحات المعلومات الثلاث المجهَّزة مسبقاً، وExplore، ومصادر البيانات الثلاثة |
| API الكتالوج | http://localhost:8000 | /cours و/cours/C0001 و/sante و/metrics : الخدمة المراقَبة، من الخارج |
| webhook | http://localhost:8090 | قائمة التنبيهات المستلمة من Alertmanager، تُحدَّث كل 10 ثوانٍ |
| Loki | http://localhost:3100/ready | يجيب ready ؛ ليس لـ Loki واجهة، نستعلمه عبر Grafana |
| Alloy | http://localhost:12345 | واجهة التشخيص الخاصة به : مكوّنات config.alloy وحالتها |
| node-exporter | http://localhost:9100/metrics | الصفحة الخام لمقاييس الجهاز المضيف |
| cAdvisor | http://localhost:8080 | المقاييس لكل حاوية ؛ /metrics للصفحة الخام |
بدء التشغيل. من lab3 :
.\labo.ps1 demarrer./labo.sh demarrerعلى جهاز الدورة، عند أول تشغيل (أسطر التنزيل والبناء محذوفة) :
== 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)ما يجب رؤيته : الأربعة Skipped Image can be built (الصور المحلية لا تُنزَّل، بل تُبنى)، ومجلدات التخزين الثلاثة المنشأة، وlabo-charge Starting فقط بعد labo-api Healthy، ثم العشرة prêt. على جهاز الدورة، استغرق demarrer 44 ثانية بعد أن أصبحت الصور في الذاكرة المؤقتة. يطلب منك السطر الأخير الانتظار دقيقتين : يحتاج Prometheus إلى بضع عمليات كشط لرسم منحنى.
قراءة 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.ما يجب رؤيته : كتلتان. Conteneurs (الحاويات) : عشرة أسطر، كلها Up … (healthy). Supervision (الإشراف) : يقرأ Prometheus أهدافه الثمانية، ويخزن 9038 سلسلة (يرتفع هذا الرقم خلال الدقائق الأولى، ثم يستقر حول 12 000 إلى 15 000 على جهاز الدورة)، ولا تنبيه ؛ يعرف API 64 دورة ؛ لم يستقبل webhook شيئاً. السطر الأخير، Labo : 10/10 services, 8/8 cibles up, 0 alertes actives.، هو الذي يجب أن تجده في نهاية كل تمرين.
Prometheus : Query وAlerts وStatus. افتح http://localhost:9090. للقائمة العلوية ثلاثة مداخل : Query وAlerts وStatus. في Status، تقترح القائمة الفرعية Target health وRule health وService discovery وRuntime & build information وTSDB status وCommand-line flags وConfiguration وAlertmanager discovery. اذهب إلى Target health : ثماني كتل، واحدة لكل مهمة، كل منها بـ 1 / 1 up، والعنوان المقروء (Endpoint)، والتسميات، وتاريخ آخر كشط، والحالة UP. على جهاز الدورة :
api
1 / 1 up
Endpoint Labels Last scrape State
http://api:8000/metrics instance="api:8000" job="api" service="api" 6.014s ago UPعد إلى Query، واكتب up في حقل الإدخال وانقر Execute (أو Enter). تحت الحقل، ثلاث علامات تبويب : Table وGraph وExplain. في Table، ثمانية أسطر بالشكل up{instance="localhost:9090", job="prometheus"} 1، كلها بقيمة 1. تحت علامات التبويب، سطر من نوع Load time: 40ms Result series: 8 يخبرك بعدد السلاسل التي استجابت. انتقل إلى Graph : ثمانية خطوط مسطحة عند 1. الوحدة 2 ستقضي بقية الوقت على هذه الصفحة.
Grafana : ثلاث لوحات معلومات جاهزة. افتح http://localhost:3000، المستخدم admin، كلمة المرور aiopsatlas2026. تعرض الصفحة الرئيسية Recent dashboards : لوحات المعلومات الثلاث المجهَّزة مسبقاً من الحقيبة، في المجلد Labo observabilite. تعطي القائمة الرئيسية (الأيقونة في أعلى اليسار) Dashboards وExplore وAlerting وConnections → Data sources. في Connections → Data sources، ثلاثة مصادر : Prometheus (افتراضي)، وLoki، وAlertmanager. يؤكد API الخاص بـ Grafana القائمة نفسها :
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افتح API catalogue — signaux dorés (API الكتالوج — الإشارات الذهبية) : الإشارات الذهبية الأربع (الحركة، الأخطاء، الكمون، التشبع) لـ API، بالإضافة إلى مقياسين للأعمال (التسجيلات، الدورات المطّلع عليها). المنحنيات مسطحة في البداية : يلزم دقيقتان من الحمل. ما يجب رؤيته : لا شيء مما تراه هنا مخزّن في Grafana. كل لوح يرسل استعلام PromQL إلى Prometheus في اللحظة التي تنظر فيها. Grafana هو الزجاج الأمامي، لا المحرك.
يُقرأ Loki في المكان نفسه. افتح Explore في القائمة، واختر المصدر Loki في المحدد في الأعلى، واكتب {service="api"} في حقل الاستعلام وشغّل بـ Run query : تتدفق أسطر JSON الخاصة بـ API، الأحدث في الأعلى، كل منها مع تسمياته. لا يعرف Loki سوى أربع تسميات في هذا المختبر، يمكن الحصول عليها عبر http://localhost:3100/loki/api/v1/labels : code وconteneur وniveau وservice. service وconteneur تأتيان من Docker، وniveau وcode يستخرجهما Alloy من الـ JSON. بدّل المحدد إلى Prometheus، واكتب up، ثم Run query : تظهر السلاسل الثماني من الخطوة 3، في جدول وفي منحنى. Explore هو المكان الذي نجرب فيه استعلاماً قبل تحويله إلى لوح (الدرس 07).
API الكتالوج، من الخارج. افتح العناوين الأربعة التالية في المتصفح، أو بـ 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 02ما يجب رؤيته : /sante هو المسار الذي يستدعيه Docker لـ healthcheck ؛ /cours/C0001 هو إحدى الدورات الـ 64 ؛ /cours/C9999 يجيب بـ 404 نظيف، يعدّه API في http_requetes_total{code="404",route="/cours/{id}"} ويكتبه في سجل WARNING ؛ /metrics هو ما يقرؤه Prometheus. كل استجابة تحمل ترويسة x-id-requete (مثلاً c5c49525ea53)، وهو المعرّف نفسه الموجود في سجل JSON لهذا الطلب.
Alertmanager وwebhook : المصابيح التحذيرية، مطفأة. افتح http://localhost:9093 : تقترح القائمة Alerts وSilences وStatus وSettings، وزراً New Silence. في التشغيل العادي، صفحة Alerts فارغة. افتح http://localhost:8090 : صفحة « Alertes reçues d'Alertmanager » (التنبيهات المستلمة من Alertmanager) مع جدول من ستة أعمدة (Reçue à، Alerte، Sévérité، État، Service، Résumé — وقت الاستلام، التنبيه، الخطورة، الحالة، الخدمة، الملخص) والسطر Aucune alerte reçue pour l'instant. (لم يُستلم أي تنبيه حتى الآن) ؛ تُحدَّث الصفحة كل 10 ثوانٍ. الصيغة الخام على http://localhost:8090/alertes.json ([]) وحالة الخدمة على http://localhost:8090/sante :
{"etat":"ok","alertes_en_memoire":0,"notifications":0,"alertes":0}ما يجب رؤيته : صفحتان فارغتان، وهذا ما نريده. تمرين هذه الوحدة يملؤهما بـ casser api.
Loki وAlloy وnode-exporter وcAdvisor : الكواليس. أربع صفحات بلا واجهة مريحة :
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"}…)ما يجب رؤيته : يجيب Loki وAlloy بكلمة واحدة ؛ إنهما يعملان لصالح Grafana، لا لصالحك مباشرة. يعرض المُصدِّران (exporters) شكل الصفحة نفسه الذي يعرضه API (# HELP و# TYPE، سطر لكل سلسلة)، مع أسطر أكثر بكثير. افتح http://localhost:8080 دون /metrics : يعيد cAdvisor التوجيه إلى /containers/، صفحة صغيرة تعرض الجهاز بأكمله (Usage Overview وCPU Total Usage وMemory Total Usage وNetwork Throughput) ورابطاً Docker Containers نحو تفاصيل كل حاوية.
قراءة سجل.
.\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"}ثم 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}}ما يجب رؤيته : يكتب API سطراً لكل طلب ؛ ويكتب مولّد الحمل ملخصاً كل 30 ثانية، حوالي 260 طلباً (قرابة 9 في الثانية)، منها حوالي عشرين 404 وبضعة 500 متعمدة. هذه الأرقام هي التي ستجدها في Prometheus بـ rate() في الوحدة 2.
الإيقاف، ثم إعادة التشغيل دون فقدان أي شيء.
.\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 reprendreيعرض docker compose ps -a حينها عشرة أسطر Exited ؛ وينتهي etat بـ Labo : 0/10 services, ?/? cibles up, ? alertes actives. (علامات ? لأن Prometheus لم يعد يستجيب). أعد تشغيل .\labo.ps1 demarrer : هذه المرة، لا تنزيل، ولا بناء، حوالي ثلاثين ثانية. في Prometheus، اكتب up وانتقل إلى Graph بنطاق ساعة واحدة : ينقطع المنحنى أثناء الإيقاف ثم يستأنف، مع بقاء التاريخ السابق سليماً. مجلد التخزين prometheus-data هو الذي احتفظ بالسلاسل.
يتوقف demarrer عند خدمة. الرسالة صريحة : Un service n'a pas démarré. Regardez son journal : .\labo.ps1 journal <service> (لم تبدأ خدمة. انظر إلى سجلها). افعل ذلك. الحالة الأكثر شيوعاً هي منفذ شُغل بين prerequis وdemarrer (برنامج آخر شُغّل في هذه الأثناء) : يرفض Docker حينها نشر المنفذ، ويكون سجل الحاوية فارغاً لأنها لم تبدأ أبداً. أعد تشغيل prerequis.
journal دون اسم خدمة. .\labo.ps1 journal وحده يعرض :
usage : .\labo.ps1 journal <prometheus|alertmanager|loki|alloy|node-exporter|cadvisor|api|webhook|charge|grafana>الأسماء العشرة الصالحة موجودة هنا ؛ إنها أسماء الخدمات في docker-compose.yml، وليست أسماء الحاويات (api، وليس labo-api). وبالمثل، يجيب .\labo.ps1 casser tout بـ usage : .\labo.ps1 casser <api|erreurs|lenteur|disque>.
يجيب Grafana بـ Unauthorized. إذا استدعيت API الخاص بـ Grafana دون تسجيل الدخول، مثلاً http://localhost:3000/api/search في علامة تبويب خاصة، تحصل على :
{"extra":null,"message":"Unauthorized","messageId":"auth.unauthorized","statusCode":401,"traceID":""}هذا طبيعي : تتطلب صفحات API جلسة أو كلمة مرور. سجّل الدخول أولاً على http://localhost:3000 (admin / aiopsatlas2026)، ثم أعد التحميل.
تعرض لوحات معلومات Grafana « No data ». سببان، بهذا الترتيب : المختبر يعمل منذ أقل من دقيقتين (انتظر) ؛ أو النطاق الزمني في أعلى اليمين يشير إلى فترة كان فيها المختبر متوقفاً (أعد ضبطه إلى « Last 15 minutes » أو « Last 1 hour »).
يعرض etat السطر Labo : 0/10 services, ?/? cibles up, ? alertes actives. المختبر متوقف. .\labo.ps1 demarrer.
تحت PowerShell، يعرض demarrer أسطراً حمراء NativeCommandError حول Container labo-api Stopping. هذه رسائل التقدم من Docker Compose، مكتوبة على مخرج الخطأ ؛ عندما يُشغَّل labo.ps1 نفسه من سكريبت آخر أو مع 2>&1، يلبسها PowerShell 5.1 ثوب الخطأ. المختبر بدأ فعلاً : تحقق بـ etat.
demarrer يُنزّل ست صور، ويبني أربع صور محلية، وينشئ شبكة وثلاثة مجلدات تخزين، ثم يشغّل عشر حاويات وينتظر فحوصات صحتها ؛ 44 ثانية على جهاز الدورة بعد أن أصبحت الصور في الذاكرة المؤقتة. لـ etat كتلتان : الحاويات (عشرة Up … (healthy)) والإشراف (8/8 أهداف، وعدد السلاسل، والتنبيهات، وحالة كل واجهة) ؛ سطره الأخير الاسمي هو Labo : 10/10 services, 8/8 cibles up, 0 alertes actives.. لـ Prometheus (9090) ثلاث صفحات : Query بعلامات تبويبها Table وGraph وExplain ؛ وAlerts ؛ وStatus → Target health بالأهداف الثمانية UP. لـ Grafana (3000، admin / aiopsatlas2026) ثلاث لوحات معلومات مجهَّزة مسبقاً في المجلد Labo observabilite وثلاثة مصادر بيانات، Prometheus افتراضياً ؛ ولا يخزن أي قياس بنفسه. يجيب API (8000) على /sante و/cours/C0001 و/metrics، وبـ 404 نظيف على دورة مجهولة، مع ترويسة x-id-requete في كل استجابة. Alertmanager (9093) وwebhook (8090) فارغان في التشغيل العادي. journal <service> يأخذ اسم الخدمة، لا اسم الحاوية. arreter يحتفظ بمجلدات التخزين : تبقى السلاسل، وينقطع منحنى up ثم يستأنف.
grafana/provisioning/. لهذا السبب يُوسم المجلد Labo observabilite بـ « managed by classic file provisioning » في API.docker compose ps, logs, stop : الأوامر التي يسلسلها labo.ps1 وlabo.sh من أجلك ؛ journal api هو docker compose logs --tail 100 api.etat، وفي Target health، وفي Alertmanager، وفي webhook، قبل الإصلاح.