deploy on the cloud and made some refactory on files
هذا الالتزام موجود في:
1
.github/workflows/deploy.yml
مباع
Normal file
1
.github/workflows/deploy.yml
مباع
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# Deploy Applications
|
||||||
17
q1-deploy-monitor/.ghaymah.json
Normal file
17
q1-deploy-monitor/.ghaymah.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"id": "bdf396c2-fdf8-45ef-9066-1486d9b4d512",
|
||||||
|
"name": "q1-deploy-monitor",
|
||||||
|
"projectId": "150648a2-a09a-4387-a3af-35f966a28292",
|
||||||
|
"ports": [
|
||||||
|
{
|
||||||
|
"expose": true,
|
||||||
|
"number": 8080
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"publicAccess": {
|
||||||
|
"enabled": true,
|
||||||
|
"domain": "auto"
|
||||||
|
},
|
||||||
|
"resourceTier": "t1",
|
||||||
|
"dockerFileName": "Dockerfile"
|
||||||
|
}
|
||||||
@@ -8,8 +8,10 @@
|
|||||||
├── Dockerfile
|
├── Dockerfile
|
||||||
├── requirements.txt
|
├── requirements.txt
|
||||||
├── .dockerignore
|
├── .dockerignore
|
||||||
|
├── .ghaymah.json
|
||||||
├── app/
|
├── app/
|
||||||
│ └── main.py # تطبيق Flask + /health + /metrics
|
│ └── main.py # تطبيق Flask + /health + /metrics
|
||||||
|
├── demo/
|
||||||
├── health-check.sh # سكربت مراقبة بلغة bash (فحص كل 30 ثانية)
|
├── health-check.sh # سكربت مراقبة بلغة bash (فحص كل 30 ثانية)
|
||||||
├── health-check.py
|
├── health-check.py
|
||||||
└── dashboard.html # لوحة مراقبة (HTML/CSS/JS) تعمل من المتصفح مباشرة
|
└── dashboard.html # لوحة مراقبة (HTML/CSS/JS) تعمل من المتصفح مباشرة
|
||||||
@@ -25,35 +27,7 @@ curl http://localhost:8080/health
|
|||||||
curl http://localhost:8080/metrics
|
curl http://localhost:8080/metrics
|
||||||
```
|
```
|
||||||
|
|
||||||
## 2) النشر على ghaymah.systems
|
## 2) تشغيل سكربت المراقبة
|
||||||
|
|
||||||
منصة الحاويات في Ghaymah تدعم النشر إما عبر ربط مستودع Git (بناء تلقائي من الـ Dockerfile) أو عبر دفع صورة جاهزة إلى سجل الحاويات الخاص بها. الخطوات العامة:
|
|
||||||
|
|
||||||
1. سجّل الدخول إلى console الخاص بـ **ghaymah.systems**.
|
|
||||||
2. من قسم **Containers**، اختر **New Service / Deploy Container**.
|
|
||||||
3. اختر مصدر النشر:
|
|
||||||
- **Git Repository**: اربط المستودع الذي يحتوي هذا المشروع (يجب أن يحتوي على `Dockerfile` في الجذر) — المنصة تبني الصورة تلقائيًا من الـ Dockerfile.
|
|
||||||
- **أو Container Registry**: ابنِ وادفع الصورة يدويًا:
|
|
||||||
```bash
|
|
||||||
docker build -t <registry>/<namespace>/sample-api:1.0 .
|
|
||||||
docker push <registry>/<namespace>/sample-api:1.0
|
|
||||||
```
|
|
||||||
ثم أدخل مسار الصورة هذا عند إنشاء الخدمة.
|
|
||||||
4. اضبط إعدادات الخدمة:
|
|
||||||
- **Port**: `8080` (نفس المنفذ في `EXPOSE` وفي `PORT` env).
|
|
||||||
- **Health Check Path**: `/health` (المنصة تستخدمه لمعرفة جاهزية الحاوية).
|
|
||||||
- **Environment Variables**: أضف `PORT=8080` إن احتاج الأمر.
|
|
||||||
- **Resources**: ابدأ بأصغر خطة (0.5 vCPU / 256-512MB) كافية لهذا التطبيق التجريبي.
|
|
||||||
5. اضغط **Deploy**. بعد اكتمال النشر ستحصل على رابط عام مثل:
|
|
||||||
`https://sample-api-xxxx.ghaymah.systems`
|
|
||||||
6. تحقق من النشر:
|
|
||||||
```bash
|
|
||||||
curl https://sample-api-xxxx.ghaymah.systems/health
|
|
||||||
```
|
|
||||||
|
|
||||||
> ملاحظة: أسماء الأزرار والحقول الدقيقة قد تختلف قليلًا حسب نسخة الواجهة الحالية على `ghaymah.systems` — الخطوات أعلاه تعكس تدفق العمل القياسي لمنصات الحاويات (Container-as-a-Service)، راجع `docs.ghaymah.cloud` لأي تفاصيل محدّثة.
|
|
||||||
|
|
||||||
## 3) تشغيل سكربت المراقبة
|
|
||||||
|
|
||||||
بعد النشر، شغّل سكربت المراقبة موجّهًا إلى الرابط العام للتطبيق:
|
بعد النشر، شغّل سكربت المراقبة موجّهًا إلى الرابط العام للتطبيق:
|
||||||
|
|
||||||
@@ -62,8 +36,8 @@ curl http://localhost:8080/metrics
|
|||||||
python health-check.py --url https://sample-api-xxxx.ghaymah.systems --interval 30
|
python health-check.py --url https://sample-api-xxxx.ghaymah.systems --interval 30
|
||||||
|
|
||||||
# أو bash
|
# أو bash
|
||||||
chmod +x monitor.sh
|
chmod +x health-check.sh
|
||||||
./monitor.sh https://sample-api-xxxx.ghaymah.systems 30
|
./health-check.sh https://sample-api-xxxx.ghaymah.systems 30
|
||||||
```
|
```
|
||||||
|
|
||||||
السكربت يقوم بـ:
|
السكربت يقوم بـ:
|
||||||
@@ -74,7 +48,7 @@ chmod +x monitor.sh
|
|||||||
|
|
||||||
يمكن تشغيله كخدمة نظام دائمة (systemd) أو كحاوية منفصلة (sidecar) بجانب التطبيق نفسه.
|
يمكن تشغيله كخدمة نظام دائمة (systemd) أو كحاوية منفصلة (sidecar) بجانب التطبيق نفسه.
|
||||||
|
|
||||||
## 4) لوحة المراقبة (Dashboard)
|
## 3) لوحة المراقبة (Dashboard)
|
||||||
|
|
||||||
افتح `dashboard.html` مباشرة في المتصفح (لا يحتاج خادمًا، ملف ثابت واحد):
|
افتح `dashboard.html` مباشرة في المتصفح (لا يحتاج خادمًا، ملف ثابت واحد):
|
||||||
|
|
||||||
@@ -90,7 +64,7 @@ chmod +x monitor.sh
|
|||||||
|
|
||||||
اللوحة تستدعي `/metrics` كل 5 ثوانٍ عبر `fetch()` مباشرة من المتصفح؛ التطبيق (`main.py`) يضيف ترويسة `Access-Control-Allow-Origin: *` لذلك لا حاجة لخادم وسيط.
|
اللوحة تستدعي `/metrics` كل 5 ثوانٍ عبر `fetch()` مباشرة من المتصفح؛ التطبيق (`main.py`) يضيف ترويسة `Access-Control-Allow-Origin: *` لذلك لا حاجة لخادم وسيط.
|
||||||
|
|
||||||
## ملاحظات إنتاجية (Production Notes)
|
## 4) ملاحظات إنتاجية (Production Notes)
|
||||||
- التطبيق يعمل بمستخدم غير جذري (`non-root user`) داخل الحاوية.
|
- التطبيق يعمل بمستخدم غير جذري (`non-root user`) داخل الحاوية.
|
||||||
- يُستخدم `gunicorn` كخادم WSGI إنتاجي بدلاً من خادم التطوير المدمج في Flask.
|
- يُستخدم `gunicorn` كخادم WSGI إنتاجي بدلاً من خادم التطوير المدمج في Flask.
|
||||||
- `HEALTHCHECK` مضمّن في الـ Dockerfile نفسه، بالإضافة إلى فحص خارجي (`health-check.py`) — طبقتا مراقبة مستقلتان.
|
- `HEALTHCHECK` مضمّن في الـ Dockerfile نفسه، بالإضافة إلى فحص خارجي (`health-check.py`) — طبقتا مراقبة مستقلتان.
|
||||||
|
|||||||
ثنائية
q1-deploy-monitor/demo/dashboard.png
Normal file
ثنائية
q1-deploy-monitor/demo/dashboard.png
Normal file
ملف ثنائي غير معروض.
|
بعد العرض: | الارتفاع: | الحجم: 90 KiB |
ثنائية
q1-deploy-monitor/demo/ghaymah.png
Normal file
ثنائية
q1-deploy-monitor/demo/ghaymah.png
Normal file
ملف ثنائي غير معروض.
|
بعد العرض: | الارتفاع: | الحجم: 231 KiB |
ثنائية
q1-deploy-monitor/demo/sample-api.png
Normal file
ثنائية
q1-deploy-monitor/demo/sample-api.png
Normal file
ملف ثنائي غير معروض.
|
بعد العرض: | الارتفاع: | الحجم: 22 KiB |
@@ -7,8 +7,8 @@ logs status + response time, and writes the latest result to a JSON
|
|||||||
file (status.json) that can be consumed by other tools or dashboards.
|
file (status.json) that can be consumed by other tools or dashboards.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
python health-check.py --url https://your-app.ghaymah.systems
|
python health-check.py --url https://q1-deploy-monitor-cad54f6feeb3.hosted.ghaymah.systems/
|
||||||
python health-check.py --url https://your-app.ghaymah.systems --interval 30
|
python health-check.py --url https://q1-deploy-monitor-cad54f6feeb3.hosted.ghaymah.systems/ --interval 30
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
#
|
#
|
||||||
# Simple bash health monitor - polls /health every 30s.
|
# Simple bash health monitor - polls /health every 30s.
|
||||||
# Usage: ./monitor.sh https://your-app.ghaymah.systems [interval_seconds]
|
# Usage: ./health-check.sh https://q1-deploy-monitor-cad54f6feeb3.hosted.ghaymah.systems/ [interval_seconds]
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
# بناء CI/CD Pipeline على غيمة (GitHub Actions + Ghaymah Container Registry)
|
# بناء CI/CD Pipeline على غيمة (GitHub Actions + Docker Registry + Ghaymah CLI)
|
||||||
|
|
||||||
## محتويات
|
## محتويات
|
||||||
```
|
```
|
||||||
.github/workflows/workflow.yml # الـ workflow الكامل
|
q3-cicd/workflow.yml # نسخة workflow كاملة مرفقة مع إجابة السؤال
|
||||||
README.md # هذا التوثيق
|
.github/workflows/deploy.yml # مسودة/نسخة قابلة للنقل إلى GitHub Actions عند الحاجة
|
||||||
|
q3-cicd/README.md # هذا التوثيق
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -18,7 +19,7 @@ build-and-push ──▶ deploy-staging ──▶ deploy-production
|
|||||||
+ رفع للسجل) بدون موافقة) مطلوبة قبل التنفيذ)
|
+ رفع للسجل) بدون موافقة) مطلوبة قبل التنفيذ)
|
||||||
```
|
```
|
||||||
|
|
||||||
- **build-and-push**: يبني صورة Docker، يشغّلها محليًا داخل الـ runner ويتحقق من `/health` (بوابة جودة أساسية) قبل رفعها فعليًا إلى **Ghaymah Container Registry**.
|
- **build-and-push**: يبني صورة Docker، يشغّلها محليًا داخل الـ runner ويتحقق من `/health` (بوابة جودة أساسية) قبل رفعها فعليًا إلى سجل صور OCI. النسخة الحالية من `workflow.yml` تستخدم Docker Hub (`docker.io`) كقيمة افتراضية، ويمكن استبداله بسجل غيمة إن كان متاحًا في الحساب.
|
||||||
- **deploy-staging**: ينشر الصورة تلقائيًا على بيئة `staging` فور نجاح البناء — بدون تدخل بشري، لأن الهدف من staging هو تحقق سريع ومستمر.
|
- **deploy-staging**: ينشر الصورة تلقائيًا على بيئة `staging` فور نجاح البناء — بدون تدخل بشري، لأن الهدف من staging هو تحقق سريع ومستمر.
|
||||||
- **deploy-production**: نفس صورة staging (بدون إعادة بناء) تُنشر على `production`، لكن **الوظيفة لا تبدأ التنفيذ إلا بعد موافقة يدوية** (تفاصيل القسم التالي).
|
- **deploy-production**: نفس صورة staging (بدون إعادة بناء) تُنشر على `production`، لكن **الوظيفة لا تبدأ التنفيذ إلا بعد موافقة يدوية** (تفاصيل القسم التالي).
|
||||||
|
|
||||||
@@ -33,7 +34,7 @@ build-and-push ──▶ deploy-staging ──▶ deploy-production
|
|||||||
2. أنشئ بيئة باسم `production` (يجب أن يطابق الاسم بالضبط ما هو مكتوب في `environment: name: production` داخل الـ workflow).
|
2. أنشئ بيئة باسم `production` (يجب أن يطابق الاسم بالضبط ما هو مكتوب في `environment: name: production` داخل الـ workflow).
|
||||||
3. فعّل **Required reviewers** وأضف الأشخاص أو الفريق المخوّل بالموافقة على نشر الإنتاج (مثال: قائد الفريق التقني أو مسؤول SRE).
|
3. فعّل **Required reviewers** وأضف الأشخاص أو الفريق المخوّل بالموافقة على نشر الإنتاج (مثال: قائد الفريق التقني أو مسؤول SRE).
|
||||||
4. (اختياري لكن موصى به) فعّل **Wait timer** (مثلاً 0-5 دقائق) كطبقة أمان إضافية، و**Deployment branches** لتقييد النشر على فرع `main` فقط.
|
4. (اختياري لكن موصى به) فعّل **Wait timer** (مثلاً 0-5 دقائق) كطبقة أمان إضافية، و**Deployment branches** لتقييد النشر على فرع `main` فقط.
|
||||||
5. أضف أسرار الإنتاج (Secrets) الخاصة بهذه البيئة تحديدًا (`GHAYMAH_API_TOKEN` لبيئة production منفصل عن نفس المتغير في staging) — هذا يمنع تسريب صلاحيات الإنتاج حتى لو تم تشغيل job آخر بالخطأ.
|
5. أضف أسرار الإنتاج (Secrets) الخاصة بهذه البيئة تحديدًا (`GHAYMAH_Email` و`GHAYMAH_PASSWORD` في النسخة الحالية، أو `GHAYMAH_API_TOKEN` إذا كان الحساب يدعم token مخصصًا للنشر) — هذا يمنع تسريب صلاحيات الإنتاج حتى لو تم تشغيل job آخر بالخطأ.
|
||||||
|
|
||||||
### كيف يعمل عمليًا
|
### كيف يعمل عمليًا
|
||||||
عندما يصل تنفيذ الـ workflow إلى job **deploy-production**، يتوقف تلقائيًا في حالة **"Waiting"** ولا تُنفَّذ أي خطوة داخله (بما فيها تسجيل الدخول لـ Ghaymah CLI) حتى يوافق أحد المراجعين المخوّلين من تبويب **Actions** في GitHub. هذا يضمن أن الكود الذي وصل فعليًا إلى staging وتحقق من صحته هو نفسه الذي يُنشر للإنتاج — دون إعادة بناء، ودون فجوة زمنية تسمح بتغييرات غير مراجعة.
|
عندما يصل تنفيذ الـ workflow إلى job **deploy-production**، يتوقف تلقائيًا في حالة **"Waiting"** ولا تُنفَّذ أي خطوة داخله (بما فيها تسجيل الدخول لـ Ghaymah CLI) حتى يوافق أحد المراجعين المخوّلين من تبويب **Actions** في GitHub. هذا يضمن أن الكود الذي وصل فعليًا إلى staging وتحقق من صحته هو نفسه الذي يُنشر للإنتاج — دون إعادة بناء، ودون فجوة زمنية تسمح بتغييرات غير مراجعة.
|
||||||
@@ -63,23 +64,30 @@ build-and-push ──▶ deploy-staging ──▶ deploy-production
|
|||||||
### أ) التثبيت (داخل الـ workflow أو محليًا)
|
### أ) التثبيت (داخل الـ workflow أو محليًا)
|
||||||
```bash
|
```bash
|
||||||
curl -fsSL https://cli.ghaymah.systems/install.sh | sh
|
curl -fsSL https://cli.ghaymah.systems/install.sh | sh
|
||||||
ghaymah --version
|
gy --version
|
||||||
```
|
```
|
||||||
> ملاحظة: عنوان التثبيت وأسماء الأوامر أعلاه مبنية على النمط القياسي لأدوات CLI الخاصة بمنصات الحاويات (deploy/login/logs). يُرجى التأكد من الأمر الدقيق ورابط التثبيت من `docs.ghaymah.cloud` أو console الحساب، حيث إن تفاصيل الواجهة قد تختلف عن الأمثلة هنا.
|
> ملاحظة: عنوان التثبيت وأسماء الأوامر أعلاه مبنية على النمط القياسي لأدوات CLI الخاصة بمنصات الحاويات (deploy/login/logs). يُرجى التأكد من الأمر الدقيق ورابط التثبيت من `docs.ghaymah.cloud` أو console الحساب، حيث إن تفاصيل الواجهة قد تختلف عن الأمثلة هنا.
|
||||||
|
|
||||||
### ب) المصادقة (Authentication)
|
### ب) المصادقة (Authentication)
|
||||||
لا تُستخدم بيانات اعتماد شخصية داخل الـ pipeline أبدًا. بدلًا من ذلك:
|
لا تُكتب بيانات الاعتماد داخل ملف الـ workflow. النسخة الحالية تستخدم أسرار GitHub التالية:
|
||||||
1. يُنشأ **API Token** مخصص لبيئة CI/CD من لوحة تحكم غيمة (Settings → API Tokens أو ما يعادلها)، بصلاحيات محدودة (نشر/سحب صور فقط، وليس صلاحيات إدارية كاملة).
|
|
||||||
2. يُخزَّن هذا التوكن كسر (Secret) في GitHub:
|
- `GHAYMAH_REGISTRY_USER` و`GHAYMAH_REGISTRY_TOKEN` لتسجيل الدخول إلى سجل الصور عبر `docker/login-action`.
|
||||||
- `GHAYMAH_REGISTRY_TOKEN` — لتسجيل الدخول لسجل الحاويات (`docker/login-action`).
|
- `GHAYMAH_Email` و`GHAYMAH_PASSWORD` لتسجيل الدخول إلى Ghaymah CLI بالأمر `gy auth login`.
|
||||||
- `GHAYMAH_API_TOKEN` — لتنفيذ أوامر `ghaymah deploy` عبر الـ CLI.
|
|
||||||
3. تسجيل الدخول داخل الـ workflow:
|
إن كان الحساب يدعم API Token مخصصًا للنشر، فالخيار الأفضل إنتاجيًا هو تخزينه كـ `GHAYMAH_API_TOKEN` بصلاحيات محدودة واستبدال خطوة تسجيل الدخول بـ:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ghaymah auth login --token "$GHAYMAH_API_TOKEN"
|
gy auth login --token "$GHAYMAH_API_TOKEN"
|
||||||
```
|
```
|
||||||
|
|
||||||
### ج) الربط مع سجل الحاويات (Container Registry)
|
### ج) الربط مع سجل الحاويات (Container Registry)
|
||||||
تسجيل الدخول لسجل الحاويات يتم عبر الأمر القياسي لـ Docker (متوافق مع أي سجل OCI، بما فيه سجل غيمة):
|
تسجيل الدخول لسجل الحاويات يتم عبر الأمر القياسي لـ Docker. في `workflow.yml` القيمة الافتراضية هي Docker Hub:
|
||||||
|
```bash
|
||||||
|
echo "$GHAYMAH_REGISTRY_TOKEN" | docker login docker.io \
|
||||||
|
--username "$GHAYMAH_REGISTRY_USER" --password-stdin
|
||||||
|
```
|
||||||
|
|
||||||
|
وإذا تم استخدام سجل غيمة بدل Docker Hub، تصبح الصيغة:
|
||||||
```bash
|
```bash
|
||||||
echo "$GHAYMAH_REGISTRY_TOKEN" | docker login registry.ghaymah.systems \
|
echo "$GHAYMAH_REGISTRY_TOKEN" | docker login registry.ghaymah.systems \
|
||||||
--username "$GHAYMAH_REGISTRY_USER" --password-stdin
|
--username "$GHAYMAH_REGISTRY_USER" --password-stdin
|
||||||
@@ -88,17 +96,18 @@ echo "$GHAYMAH_REGISTRY_TOKEN" | docker login registry.ghaymah.systems \
|
|||||||
|
|
||||||
### د) أوامر النشر الأساسية
|
### د) أوامر النشر الأساسية
|
||||||
```bash
|
```bash
|
||||||
# نشر صورة على خدمة معيّنة (staging أو production حسب --env)
|
# إنشاء/تحديد مشروع ثم تهيئة التطبيق وتشغيله
|
||||||
ghaymah deploy --service <service-name> --image <registry>/<namespace>/<image>:<tag> --env <staging|production> --wait
|
gy resource project create -s .name=<project-name>
|
||||||
|
gy resource app init . -p <project-id>
|
||||||
|
gy resource app launch
|
||||||
|
|
||||||
# متابعة سجلات الخدمة بعد النشر
|
# متابعة سجلات الخدمة بعد النشر
|
||||||
ghaymah logs --service <service-name> --follow
|
gy resource app logs --follow
|
||||||
|
|
||||||
# التحقق من حالة الخدمة والنسخ الحالية
|
# التحقق من حالة الخدمة والنسخ الحالية
|
||||||
ghaymah status --service <service-name>
|
gy resource app get
|
||||||
|
|
||||||
# التراجع عن نشر فاشل (Rollback) إلى آخر نسخة مستقرة
|
# ملاحظة: قد تختلف أوامر السجلات/الحالة/rollback الدقيقة حسب إصدار Ghaymah CLI.
|
||||||
ghaymah rollback --service <service-name>
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### هـ) أفضل الممارسات المطبّقة في هذا الـ Pipeline
|
### هـ) أفضل الممارسات المطبّقة في هذا الـ Pipeline
|
||||||
|
|||||||
@@ -1,30 +1,32 @@
|
|||||||
name: CI/CD - Build, Push, Deploy (Ghaymah)
|
name: CI/CD - Build, Push, Deploy (Ghaymah)
|
||||||
|
|
||||||
# يعمل تلقائيًا عند الدفع لفرع main، أو يدويًا لأي فرع/بيئة عبر workflow_dispatch
|
# Runs automatically on pushes to the main branch, or manually for any branch/environment via workflow_dispatch
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: ["main"]
|
branches: ["main"]
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
image_tag:
|
image_tag:
|
||||||
description: "وسم اختياري إضافي للصورة (افتراضيًا: git SHA)"
|
description: "Optional extra image tag (default: git SHA)"
|
||||||
required: false
|
required: false
|
||||||
default: ""
|
default: ""
|
||||||
|
|
||||||
# صلاحيات أقل ما يمكن (least privilege)
|
# Least privilege permissions
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
packages: write
|
packages: write
|
||||||
|
|
||||||
env:
|
env:
|
||||||
# عنوان سجل الحاويات الخاص بغيمة - عدّله حسب مشروعك
|
# Docker Hub registry address
|
||||||
GHAYMAH_REGISTRY: registry.ghaymah.systems
|
DOCKER_HUB_REGISTRY: docker.io
|
||||||
GHAYMAH_NAMESPACE: my-team
|
GHAYMAH_NAMESPACE: my-team
|
||||||
IMAGE_NAME: sample-api
|
IMAGE_NAME: sample-api
|
||||||
|
PROJECT_STAGING_NAME: sample-api-staging
|
||||||
|
PROJECT_PRODUCTION_NAME: sample-api-production
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
# ---------------------------------------------------------------------
|
# ---------------------------------------------------------------------
|
||||||
# 1) بناء الصورة واختبارها ورفعها إلى Ghaymah Container Registry
|
# 1) Build the image, test it, and push it to Docker Hub
|
||||||
# ---------------------------------------------------------------------
|
# ---------------------------------------------------------------------
|
||||||
build-and-push:
|
build-and-push:
|
||||||
name: Build & Push Image
|
name: Build & Push Image
|
||||||
@@ -33,7 +35,7 @@ jobs:
|
|||||||
image_ref: ${{ steps.vars.outputs.image_ref }}
|
image_ref: ${{ steps.vars.outputs.image_ref }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5.0.0
|
||||||
|
|
||||||
- name: Set image tag variables
|
- name: Set image tag variables
|
||||||
id: vars
|
id: vars
|
||||||
@@ -41,18 +43,18 @@ jobs:
|
|||||||
SHORT_SHA=$(echo "${GITHUB_SHA}" | cut -c1-7)
|
SHORT_SHA=$(echo "${GITHUB_SHA}" | cut -c1-7)
|
||||||
TAG="${{ github.event.inputs.image_tag }}"
|
TAG="${{ github.event.inputs.image_tag }}"
|
||||||
if [ -z "$TAG" ]; then TAG="$SHORT_SHA"; fi
|
if [ -z "$TAG" ]; then TAG="$SHORT_SHA"; fi
|
||||||
IMAGE_REF="${GHAYMAH_REGISTRY}/${GHAYMAH_NAMESPACE}/${IMAGE_NAME}:${TAG}"
|
IMAGE_REF="${DOCKER_HUB_REGISTRY}/${GHAYMAH_NAMESPACE}/${IMAGE_NAME}:${TAG}"
|
||||||
echo "image_ref=${IMAGE_REF}" >> "$GITHUB_OUTPUT"
|
echo "image_ref=${IMAGE_REF}" >> "$GITHUB_OUTPUT"
|
||||||
echo "Building: ${IMAGE_REF}"
|
echo "Building: ${IMAGE_REF}"
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
# تسجيل الدخول إلى سجل حاويات غيمة عبر بيانات اعتماد مخزّنة كـ GitHub Secrets
|
# Log in to Docker Hub using credentials stored as GitHub Secrets
|
||||||
- name: Log in to Ghaymah Container Registry
|
- name: Log in to Ghaymah Container Registry
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.GHAYMAH_REGISTRY }}
|
registry: ${{ env.DOCKER_HUB_REGISTRY }}
|
||||||
username: ${{ secrets.GHAYMAH_REGISTRY_USER }}
|
username: ${{ secrets.GHAYMAH_REGISTRY_USER }}
|
||||||
password: ${{ secrets.GHAYMAH_REGISTRY_TOKEN }}
|
password: ${{ secrets.GHAYMAH_REGISTRY_TOKEN }}
|
||||||
|
|
||||||
@@ -64,11 +66,11 @@ jobs:
|
|||||||
load: true
|
load: true
|
||||||
tags: |
|
tags: |
|
||||||
${{ steps.vars.outputs.image_ref }}
|
${{ steps.vars.outputs.image_ref }}
|
||||||
${{ env.GHAYMAH_REGISTRY }}/${{ env.GHAYMAH_NAMESPACE }}/${{ env.IMAGE_NAME }}:latest
|
${{ env.DOCKER_HUB_REGISTRY }}/${{ env.GHAYMAH_NAMESPACE }}/${{ env.IMAGE_NAME }}:latest
|
||||||
cache-from: type=gha
|
cache-from: type=gha
|
||||||
cache-to: type=gha,mode=max
|
cache-to: type=gha,mode=max
|
||||||
|
|
||||||
# اختبار سريع للتأكد أن /health يستجيب قبل الرفع للسجل (بوابة جودة أساسية)
|
# Quick smoke test to confirm /health responds before pushing
|
||||||
- name: Smoke test the built image
|
- name: Smoke test the built image
|
||||||
run: |
|
run: |
|
||||||
docker run -d --name smoke -p 8080:8080 ${{ steps.vars.outputs.image_ref }}
|
docker run -d --name smoke -p 8080:8080 ${{ steps.vars.outputs.image_ref }}
|
||||||
@@ -86,10 +88,10 @@ jobs:
|
|||||||
push: true
|
push: true
|
||||||
tags: |
|
tags: |
|
||||||
${{ steps.vars.outputs.image_ref }}
|
${{ steps.vars.outputs.image_ref }}
|
||||||
${{ env.GHAYMAH_REGISTRY }}/${{ env.GHAYMAH_NAMESPACE }}/${{ env.IMAGE_NAME }}:latest
|
${{ env.DOCKER_HUB_REGISTRY }}/${{ env.GHAYMAH_NAMESPACE }}/${{ env.IMAGE_NAME }}:latest
|
||||||
|
|
||||||
# ---------------------------------------------------------------------
|
# ---------------------------------------------------------------------
|
||||||
# 2) نشر تلقائي على STAGING فور نجاح البناء - بدون موافقة يدوية
|
# 2) Automatic deployment to STAGING right after a successful build - no manual approval
|
||||||
# ---------------------------------------------------------------------
|
# ---------------------------------------------------------------------
|
||||||
deploy-staging:
|
deploy-staging:
|
||||||
name: Deploy to Staging
|
name: Deploy to Staging
|
||||||
@@ -97,62 +99,64 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
environment:
|
environment:
|
||||||
name: staging
|
name: staging
|
||||||
url: https://sample-api-staging.ghaymah.systems
|
|
||||||
steps:
|
steps:
|
||||||
- name: Install Ghaymah CLI
|
- name: Install Ghaymah CLI
|
||||||
run: |
|
run: |
|
||||||
curl -fsSL https://cli.ghaymah.systems/install.sh | sh
|
curl -fsSL https://cli.ghaymah.systems/install.sh | sh
|
||||||
ghaymah --version
|
gy version
|
||||||
|
|
||||||
- name: Authenticate Ghaymah CLI
|
- name: Authenticate Ghaymah CLI
|
||||||
run: ghaymah auth login --token "${{ secrets.GHAYMAH_API_TOKEN }}"
|
run: gy auth login -e "${{ secrets.GHAYMAH_Email }}" -p "${{ secrets.GHAYMAH_PASSWORD }}"
|
||||||
|
|
||||||
- name: Deploy image to staging service
|
- name: create project
|
||||||
run: |
|
run: gy resource project create -s .name=${{ env.PROJECT_STAGING_NAME }} || true
|
||||||
ghaymah deploy \
|
|
||||||
--service sample-api-staging \
|
|
||||||
--image "${{ needs.build-and-push.outputs.image_ref }}" \
|
|
||||||
--env staging \
|
|
||||||
--wait
|
|
||||||
|
|
||||||
- name: Verify staging health
|
- name: get project id
|
||||||
|
id: get_project_id
|
||||||
run: |
|
run: |
|
||||||
curl -sf https://sample-api-staging.ghaymah.systems/health
|
echo "PROJECT_ID=$(gy resource project get | grep -oP '"id"\s*:\s*"\K[^"]+')" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: initialize application in Ghaymah
|
||||||
|
run: gy resource app init . -p ${{ env.PROJECT_ID }}
|
||||||
|
|
||||||
|
- name: Deploy Application to Staging
|
||||||
|
run: |
|
||||||
|
gy resource app launch
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------
|
# ---------------------------------------------------------------------
|
||||||
# 3) نشر على PRODUCTION - يتطلب موافقة يدوية (Manual Approval)
|
# 3) Deploy to PRODUCTION - requires manual approval
|
||||||
# الموافقة تُنفَّذ عبر GitHub Environment "production" المحمي بمراجعين
|
# Approval is handled by the protected GitHub Environment "production"
|
||||||
# مطلوبين (Required Reviewers) من إعدادات المستودع، وليس بكود مخصص.
|
# with Required Reviewers in repository settings, not by custom code.
|
||||||
# ---------------------------------------------------------------------
|
# ---------------------------------------------------------------------
|
||||||
deploy-production:
|
deploy-production:
|
||||||
name: Deploy to Production (Manual Approval Required)
|
name: Deploy to Production (Manual Approval Required)
|
||||||
needs: [build-and-push, deploy-staging]
|
needs: [build-and-push, deploy-staging]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
environment:
|
environment:
|
||||||
name: production # <-- هذا السطر يفعّل بوابة الموافقة اليدوية المضبوطة في إعدادات المستودع
|
name: production # This line enables the manual approval gate configured in repository settings
|
||||||
url: https://sample-api.ghaymah.systems
|
|
||||||
steps:
|
steps:
|
||||||
- name: Install Ghaymah CLI
|
- name: Install Ghaymah CLI
|
||||||
run: |
|
run: |
|
||||||
curl -fsSL https://cli.ghaymah.systems/install.sh | sh
|
curl -fsSL https://cli.ghaymah.systems/install.sh | sh
|
||||||
ghaymah --version
|
gy version
|
||||||
|
|
||||||
- name: Authenticate Ghaymah CLI
|
- name: Authenticate Ghaymah CLI
|
||||||
run: ghaymah auth login --token "${{ secrets.GHAYMAH_API_TOKEN }}"
|
run: gy auth login -e "${{ secrets.GHAYMAH_Email }}" -p "${{ secrets.GHAYMAH_PASSWORD }}"
|
||||||
|
|
||||||
- name: Deploy image to production service
|
|
||||||
run: |
|
|
||||||
ghaymah deploy \
|
|
||||||
--service sample-api-production \
|
|
||||||
--image "${{ needs.build-and-push.outputs.image_ref }}" \
|
|
||||||
--env production \
|
|
||||||
--strategy rolling \
|
|
||||||
--wait
|
|
||||||
|
|
||||||
- name: Verify production health
|
- name: create project
|
||||||
run: |
|
run: gy resource project create -s .name=${{ env.PROJECT_PRODUCTION_NAME }} || true
|
||||||
curl -sf https://sample-api.ghaymah.systems/health
|
|
||||||
|
|
||||||
- name: Post-deploy smoke check on /metrics
|
- name: get project id
|
||||||
|
id: get_project_id
|
||||||
run: |
|
run: |
|
||||||
curl -sf https://sample-api.ghaymah.systems/metrics
|
echo "PROJECT_ID=$(gy resource project get | grep -oP '"id"\s*:\s*"\K[^"]+')" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: initialize application in Ghaymah
|
||||||
|
run: gy resource app init . -p ${{ env.PROJECT_ID }}
|
||||||
|
|
||||||
|
- name: Deploy Application to Production
|
||||||
|
run: |
|
||||||
|
gy resource app launch
|
||||||
|
|
||||||
|
|||||||
17
q5-mithal-monitor/.ghaymah.json
Normal file
17
q5-mithal-monitor/.ghaymah.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"id": "08631d77-6ab4-4956-87c9-2c56db25c940",
|
||||||
|
"name": "q5-mithal-monitor",
|
||||||
|
"projectId": "150648a2-a09a-4387-a3af-35f966a28292",
|
||||||
|
"ports": [
|
||||||
|
{
|
||||||
|
"expose": true,
|
||||||
|
"number": 8080
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"publicAccess": {
|
||||||
|
"enabled": true,
|
||||||
|
"domain": "auto"
|
||||||
|
},
|
||||||
|
"resourceTier": "t1",
|
||||||
|
"dockerFileName": "Dockerfile"
|
||||||
|
}
|
||||||
9
q5-mithal-monitor/Dockerfile
Normal file
9
q5-mithal-monitor/Dockerfile
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
FROM python:3.11-slim
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY monitor.py dashboard.html /app/
|
||||||
|
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
|
CMD ["python", "monitor.py"]
|
||||||
77
q5-mithal-monitor/README.md
Normal file
77
q5-mithal-monitor/README.md
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
# مراقبة mithal.space ولوحة متابعة مباشرة
|
||||||
|
|
||||||
|
حل مستقل لمراقبة موقع `mithal.space` بدون أي مكتبات خارجية. يشغّل السكربت فحوصات دورية، يخزّن النتائج محليًا بصيغة JSON Lines، ويقدّم لوحة متابعة عبر HTTP.
|
||||||
|
|
||||||
|
## محتويات المشروع
|
||||||
|
|
||||||
|
```
|
||||||
|
.
|
||||||
|
├── Dockerfile
|
||||||
|
├── .ghaymah.json
|
||||||
|
├── monitor.py # فحوصات Latency/Uptime/DNS/SSL/Search + خادم HTTP
|
||||||
|
├── dashboard.html # لوحة متابعة مباشرة
|
||||||
|
└── demo/ # لقطات توضيحية للتشغيل واللوحة
|
||||||
|
```
|
||||||
|
|
||||||
|
## الفحوصات المنفذة
|
||||||
|
|
||||||
|
- **Latency/Uptime:** فحص الصفحة الرئيسية وقياس زمن الاستجابة.
|
||||||
|
- **DNS:** قياس زمن تحليل اسم النطاق.
|
||||||
|
- **SSL:** التحقق من صلاحية الشهادة وعدد الأيام المتبقية.
|
||||||
|
- **Search:** إرسال طلب بحث فعلي إلى مسار البحث وقياس الاستجابة.
|
||||||
|
|
||||||
|
## التشغيل المحلي
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd q5-mithal-monitor
|
||||||
|
python monitor.py --interval 60 --port 8080
|
||||||
|
```
|
||||||
|
|
||||||
|
ثم افتح:
|
||||||
|
|
||||||
|
```text
|
||||||
|
http://localhost:8080
|
||||||
|
```
|
||||||
|
|
||||||
|
المسارات المتاحة:
|
||||||
|
|
||||||
|
- `/` أو `/dashboard.html`: لوحة المتابعة.
|
||||||
|
- `/api/metrics`: آخر المقاييس مجمّعة بصيغة JSON.
|
||||||
|
- `/health`: فحص صحة للخدمة نفسها.
|
||||||
|
|
||||||
|
لتنفيذ فحص واحد فقط بدون تشغيل الخادم:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python monitor.py --once
|
||||||
|
```
|
||||||
|
|
||||||
|
## التخصيص
|
||||||
|
|
||||||
|
يمكن تعديل الهدف وسلوك البحث عبر متغيرات البيئة:
|
||||||
|
|
||||||
|
| المتغير | الافتراضي | الغرض |
|
||||||
|
|---|---|---|
|
||||||
|
| `TARGET_URL` | `https://mithal.space` | الموقع المراد مراقبته |
|
||||||
|
| `SEARCH_PATH` | `/search` | مسار البحث |
|
||||||
|
| `SEARCH_QUERY_PARAM` | `q` | اسم باراميتر البحث |
|
||||||
|
| `SEARCH_QUERY_VALUE` | `test` | قيمة البحث التجريبية |
|
||||||
|
| `REQUEST_TIMEOUT` | `10` | مهلة الطلب بالثواني |
|
||||||
|
| `DATA_FILE` | `data.jsonl` | ملف تخزين النتائج |
|
||||||
|
| `MAX_RECORDS` | `3000` | أقصى عدد سجلات محفوظة |
|
||||||
|
| `PORT` | `8080` | منفذ لوحة المتابعة |
|
||||||
|
|
||||||
|
## النشر على غيمة
|
||||||
|
|
||||||
|
الصورة جاهزة للبناء مباشرة من `Dockerfile`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker build -t mithal-monitor:latest .
|
||||||
|
docker run --rm -p 8080:8080 mithal-monitor:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
عند إنشاء الخدمة على Ghaymah Containers:
|
||||||
|
|
||||||
|
- اضبط المنفذ على `8080`.
|
||||||
|
- اضبط Health Check Path على `/health`.
|
||||||
|
- مرّر متغير `TARGET_URL` إذا أردت مراقبة نطاق مختلف.
|
||||||
|
- افتح الرابط العام للخدمة لعرض `dashboard.html`.
|
||||||
ثنائية
q5-mithal-monitor/demo/CLI.png
Normal file
ثنائية
q5-mithal-monitor/demo/CLI.png
Normal file
ملف ثنائي غير معروض.
|
بعد العرض: | الارتفاع: | الحجم: 64 KiB |
ثنائية
q5-mithal-monitor/demo/dashboard.png
Normal file
ثنائية
q5-mithal-monitor/demo/dashboard.png
Normal file
ملف ثنائي غير معروض.
|
بعد العرض: | الارتفاع: | الحجم: 76 KiB |
المرجع في مشكلة جديدة
حظر مستخدم