deploy on the cloud and made some refactory on files

هذا الالتزام موجود في:
2026-07-27 18:37:20 +03:00
الأصل 80980bbf16
التزام 91d8581c6e
15 ملفات معدلة مع 210 إضافات و102 حذوفات

عرض الملف

@@ -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 الكامل
README.md # هذا التوثيق
q3-cicd/workflow.yml # نسخة workflow كاملة مرفقة مع إجابة السؤال
.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-production**: نفس صورة staging (بدون إعادة بناء) تُنشر على `production`، لكن **الوظيفة لا تبدأ التنفيذ إلا بعد موافقة يدوية** (تفاصيل القسم التالي).
@@ -33,7 +34,7 @@ build-and-push ──▶ deploy-staging ──▶ deploy-production
2. أنشئ بيئة باسم `production` (يجب أن يطابق الاسم بالضبط ما هو مكتوب في `environment: name: production` داخل الـ workflow).
3. فعّل **Required reviewers** وأضف الأشخاص أو الفريق المخوّل بالموافقة على نشر الإنتاج (مثال: قائد الفريق التقني أو مسؤول SRE).
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 وتحقق من صحته هو نفسه الذي يُنشر للإنتاج — دون إعادة بناء، ودون فجوة زمنية تسمح بتغييرات غير مراجعة.
@@ -63,23 +64,30 @@ build-and-push ──▶ deploy-staging ──▶ deploy-production
### أ) التثبيت (داخل الـ workflow أو محليًا)
```bash
curl -fsSL https://cli.ghaymah.systems/install.sh | sh
ghaymah --version
gy --version
```
> ملاحظة: عنوان التثبيت وأسماء الأوامر أعلاه مبنية على النمط القياسي لأدوات CLI الخاصة بمنصات الحاويات (deploy/login/logs). يُرجى التأكد من الأمر الدقيق ورابط التثبيت من `docs.ghaymah.cloud` أو console الحساب، حيث إن تفاصيل الواجهة قد تختلف عن الأمثلة هنا.
### ب) المصادقة (Authentication)
لا تُستخدم بيانات اعتماد شخصية داخل الـ pipeline أبدًا. بدلًا من ذلك:
1. يُنشأ **API Token** مخصص لبيئة CI/CD من لوحة تحكم غيمة (Settings → API Tokens أو ما يعادلها)، بصلاحيات محدودة (نشر/سحب صور فقط، وليس صلاحيات إدارية كاملة).
2. يُخزَّن هذا التوكن كسر (Secret) في GitHub:
- `GHAYMAH_REGISTRY_TOKEN` — لتسجيل الدخول لسجل الحاويات (`docker/login-action`).
- `GHAYMAH_API_TOKEN` — لتنفيذ أوامر `ghaymah deploy` عبر الـ CLI.
3. تسجيل الدخول داخل الـ workflow:
لا تُكتب بيانات الاعتماد داخل ملف الـ workflow. النسخة الحالية تستخدم أسرار GitHub التالية:
- `GHAYMAH_REGISTRY_USER` و`GHAYMAH_REGISTRY_TOKEN` لتسجيل الدخول إلى سجل الصور عبر `docker/login-action`.
- `GHAYMAH_Email` و`GHAYMAH_PASSWORD` لتسجيل الدخول إلى Ghaymah CLI بالأمر `gy auth login`.
إن كان الحساب يدعم API Token مخصصًا للنشر، فالخيار الأفضل إنتاجيًا هو تخزينه كـ `GHAYMAH_API_TOKEN` بصلاحيات محدودة واستبدال خطوة تسجيل الدخول بـ:
```bash
ghaymah auth login --token "$GHAYMAH_API_TOKEN"
gy auth login --token "$GHAYMAH_API_TOKEN"
```
### ج) الربط مع سجل الحاويات (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
echo "$GHAYMAH_REGISTRY_TOKEN" | docker login registry.ghaymah.systems \
--username "$GHAYMAH_REGISTRY_USER" --password-stdin
@@ -88,17 +96,18 @@ echo "$GHAYMAH_REGISTRY_TOKEN" | docker login registry.ghaymah.systems \
### د) أوامر النشر الأساسية
```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) إلى آخر نسخة مستقرة
ghaymah rollback --service <service-name>
# ملاحظة: قد تختلف أوامر السجلات/الحالة/rollback الدقيقة حسب إصدار Ghaymah CLI.
```
### هـ) أفضل الممارسات المطبّقة في هذا الـ Pipeline

عرض الملف

@@ -1,30 +1,32 @@
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:
push:
branches: ["main"]
workflow_dispatch:
inputs:
image_tag:
description: "وسم اختياري إضافي للصورة (افتراضيًا: git SHA)"
description: "Optional extra image tag (default: git SHA)"
required: false
default: ""
# صلاحيات أقل ما يمكن (least privilege)
# Least privilege permissions
permissions:
contents: read
packages: write
env:
# عنوان سجل الحاويات الخاص بغيمة - عدّله حسب مشروعك
GHAYMAH_REGISTRY: registry.ghaymah.systems
# Docker Hub registry address
DOCKER_HUB_REGISTRY: docker.io
GHAYMAH_NAMESPACE: my-team
IMAGE_NAME: sample-api
PROJECT_STAGING_NAME: sample-api-staging
PROJECT_PRODUCTION_NAME: sample-api-production
jobs:
# ---------------------------------------------------------------------
# 1) بناء الصورة واختبارها ورفعها إلى Ghaymah Container Registry
# 1) Build the image, test it, and push it to Docker Hub
# ---------------------------------------------------------------------
build-and-push:
name: Build & Push Image
@@ -33,7 +35,7 @@ jobs:
image_ref: ${{ steps.vars.outputs.image_ref }}
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v5.0.0
- name: Set image tag variables
id: vars
@@ -41,18 +43,18 @@ jobs:
SHORT_SHA=$(echo "${GITHUB_SHA}" | cut -c1-7)
TAG="${{ github.event.inputs.image_tag }}"
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 "Building: ${IMAGE_REF}"
- name: Set up Docker Buildx
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
uses: docker/login-action@v3
with:
registry: ${{ env.GHAYMAH_REGISTRY }}
registry: ${{ env.DOCKER_HUB_REGISTRY }}
username: ${{ secrets.GHAYMAH_REGISTRY_USER }}
password: ${{ secrets.GHAYMAH_REGISTRY_TOKEN }}
@@ -64,11 +66,11 @@ jobs:
load: true
tags: |
${{ 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-to: type=gha,mode=max
# اختبار سريع للتأكد أن /health يستجيب قبل الرفع للسجل (بوابة جودة أساسية)
# Quick smoke test to confirm /health responds before pushing
- name: Smoke test the built image
run: |
docker run -d --name smoke -p 8080:8080 ${{ steps.vars.outputs.image_ref }}
@@ -86,10 +88,10 @@ jobs:
push: true
tags: |
${{ 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:
name: Deploy to Staging
@@ -97,62 +99,64 @@ jobs:
runs-on: ubuntu-latest
environment:
name: staging
url: https://sample-api-staging.ghaymah.systems
steps:
- name: Install Ghaymah CLI
run: |
curl -fsSL https://cli.ghaymah.systems/install.sh | sh
ghaymah --version
gy version
- 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
run: |
ghaymah deploy \
--service sample-api-staging \
--image "${{ needs.build-and-push.outputs.image_ref }}" \
--env staging \
--wait
- name: create project
run: gy resource project create -s .name=${{ env.PROJECT_STAGING_NAME }} || true
- name: Verify staging health
- name: get project id
id: get_project_id
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)
# الموافقة تُنفَّذ عبر GitHub Environment "production" المحمي بمراجعين
# مطلوبين (Required Reviewers) من إعدادات المستودع، وليس بكود مخصص.
# 3) Deploy to PRODUCTION - requires manual approval
# Approval is handled by the protected GitHub Environment "production"
# with Required Reviewers in repository settings, not by custom code.
# ---------------------------------------------------------------------
deploy-production:
name: Deploy to Production (Manual Approval Required)
needs: [build-and-push, deploy-staging]
runs-on: ubuntu-latest
environment:
name: production # <-- هذا السطر يفعّل بوابة الموافقة اليدوية المضبوطة في إعدادات المستودع
url: https://sample-api.ghaymah.systems
name: production # This line enables the manual approval gate configured in repository settings
steps:
- name: Install Ghaymah CLI
run: |
curl -fsSL https://cli.ghaymah.systems/install.sh | sh
ghaymah --version
gy version
- 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
run: |
curl -sf https://sample-api.ghaymah.systems/health
- name: create project
run: gy resource project create -s .name=${{ env.PROJECT_PRODUCTION_NAME }} || true
- name: Post-deploy smoke check on /metrics
- name: get project id
id: get_project_id
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