إدارة المخرجات وهندسة الإصدارات

مشروع: تصميم عملية إصدار متكاملة

28 دقيقة الدرس 10 من 28

مشروع: تصميم عملية إصدار متكاملة

كل ما تعلمناه في هذا الفصل — الإصدار الدلالي، ومستودعات الحزم، وبوابات الترقية، وسجلات التغييرات، وإجراءات الإصلاح العاجل، وقطارات الإصدار — يتلاقى هنا. هذا الدرس الختامي يأخذك خطوة بخطوة في تصميم عملية إصدار متكاملة وجاهزة للإنتاج لمنصة واقعية: منصة SaaS متعددة الخدمات تضم واجهة REST API عامة، وواجهة ويب، وحزمة SDK للمطورين، وأداة سطر أوامر CLI. ستحدد نظام الإصدار والحزم والترقية لكامل خط المنتج من البداية إلى النهاية، ثم تُرسّخ ذلك في إعدادات قابلة للتنفيذ.

لماذا هذا مهم على نطاق شركات التقنية الكبرى: عملية الإصدار السيئة التصميم لا تُبطئ الفرق فحسب، بل تخلق تبايناً في الإصدارات بين الخدمات، وتجعل التراجع عن التغييرات مستحيلاً، وتُنتج نشرات غير قابلة للتتبع، وتُعطّل عملاء SDK عند الترقيات. لهذا السبب بالتحديد تنشر شركات مثل Google وStripe وNetflix مواصفات داخلية مفصّلة لهندسة الإصدارات. هذا الدرس يعلمك كيف تبني واحدة.

الخطوة الأولى: تحديد خط المنتج ونظام الإصدار

قبل كتابة أي pipeline، رسّم كل حزمة قابلة للإصدار وحدد لها نظام إصدار مناسب. في منصتنا النموذجية — Orion SaaS — يتكون خط المنتج من:

  • orion-api — واجهة REST API (تُنشر داخلياً، بنظام semver مستقل)
  • orion-web — واجهة React للمستخدمين (تُنشر على CDN، بنظام CalVer على شكل YYYY.MM.PATCH)
  • orion-sdk-go — وحدة Go عامة (semver صارم، الإصدارات الرئيسية v2+ في مسار الوحدة)
  • orion-cli — أداة سطر الأوامر يُوزَّع عبر Homebrew وGitHub Releases (semver، ثنائيات موقّعة)
  • orion-helm — مخطط Helm للنشر الذاتي (semver، إصدار المخطط منفصل عن appVersion)

لكل حزمة إصدارها الخاص، وإيقاعها الزمني الخاص، ومستودعها الخاص. لا تُجبر جميع المكونات على رقم إصدار موحد. تغيير مُكسِر في CLI لا يستدعي رفع الإصدار إلى v3.0.0 في API مستقر لم يتغير فيه شيء.

# مصفوفة الإصدارات — أضفها إلى docs/RELEASE.md وطبّقها في CI # Component Scheme Repository Cadence # orion-api semver ECR (Docker) CD from main # orion-web YYYY.MM.PATCH ECR + S3 (CDN) CD from main # orion-sdk-go semver pkg.go.dev/GitHub Monthly train # orion-cli semver GitHub Releases Monthly train (same as SDK) # orion-helm semver OCI ECR repo Follows API minor version

الخطوة الثانية: تعريف الحزم

كل مكون ينتج نوعاً محدداً من الحزم. حدد ذلك بوضوح حتى يعرف كل فرد في الفريق وكل خطوة في pipeline ماذا يبني وأين يدفع.

# orion-api: صورة Docker متعددة المنصات تُدفع إلى ECR docker build \ --label "org.opencontainers.image.version=${VERSION}" \ --label "org.opencontainers.image.revision=${GIT_SHA}" \ --label "org.opencontainers.image.created=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ --tag "123456789.dkr.ecr.us-east-1.amazonaws.com/orion-api:${VERSION}" \ --tag "123456789.dkr.ecr.us-east-1.amazonaws.com/orion-api:latest" \ --platform linux/amd64,linux/arm64 \ -f docker/api/Dockerfile . # orion-sdk-go: وسم Git هو الحزمة بذاته على commit نظيف git tag "v${VERSION}" git push origin "v${VERSION}" GOPROXY=proxy.golang.org go list -m "github.com/orion/orion-sdk-go@v${VERSION}" # orion-cli: ثنائيات مترجمة لمنصات متعددة مع بصمات SHA256، موقّعة بـ cosign goreleaser release --clean # orion-helm: دفع المخطط كحزمة OCI إلى ECR helm package charts/orion --version "${CHART_VERSION}" --app-version "${APP_VERSION}" helm push orion-${CHART_VERSION}.tgz oci://123456789.dkr.ecr.us-east-1.amazonaws.com/charts
Orion Product Line — Artifact Map orion-api (Git) orion-web (Git) orion-sdk-go (Git) orion-cli (Git) orion-helm (Git) ECR (Docker Image) :1.4.2 / :latest ECR + S3 (CDN) 2026.06.3 pkg.go.dev / GitHub v2.1.0 (git tag) GitHub Releases v1.9.0 + cosign sig ECR OCI (Helm) chart 1.4.0 Promotion Pipeline dev → staging → prod Gate: smoke tests Gate: canary + SLOs Gate: security scan Gate: manual approval (required for major bumps)
خط منتج Orion: خمسة مكونات بأنواع حزم ومستودعات مختلفة تغذي pipeline ترقية موحداً.

الخطوة الثالثة: تصميم pipeline الترقية

pipeline الترقية ينقل حزمة غير قابلة للتغيير عبر البيئات. الحزمة ذاتها لا تتغير أبداً — ما يتغير هو وسم البيئة أو قيمة Kubernetes. حدد بواباتك بوضوح: ما الذي يجب أن يتحقق حتى تنتقل البنية إلى المرحلة التالية؟

  • dev — ترقية تلقائية عند كل PR مُدمَج. اجتياز اختبارات الوحدة والفحص الساكن. اختبارات الدخان لا تتجاوز 5 دقائق.
  • staging — ترقية بعد اجتياز اختبارات dev. اختبارات التكامل والعقود الكاملة. المسح الأمني (Trivy وGrype) يجب ألا يُعيد أي ثغرة عالية أو حرجة.
  • canary — لـorion-api: 5% من حركة الإنتاج تُوجَّه للإصدار الجديد لمدة 30 دقيقة. معدل الأخطاء وزمن استجابة p99 يجب ألا يتراجعا.
  • production — نشر كامل. يتطلب موافقة يدوية من مهندس الإصدار لأي رفع minor أو major. الإصلاحات patch تُرقّى تلقائياً بعد اجتياز canary.
# GitHub Actions — مرحلة الترقية من staging إلى canary promote-to-canary: needs: staging-tests environment: canary runs-on: ubuntu-latest steps: - name: Verify no critical CVEs run: | grype "123456789.dkr.ecr.us-east-1.amazonaws.com/orion-api:${{ env.VERSION }}" \ --fail-on high - name: Update Helm values — canary weight 5% run: | helm upgrade orion-canary oci://123456789.dkr.ecr.us-east-1.amazonaws.com/charts/orion \ --version "${{ env.CHART_VERSION }}" \ --set image.tag="${{ env.VERSION }}" \ --set canary.enabled=true \ --set canary.weight=5 \ --namespace production \ --wait --timeout 5m - name: Run SLO gate (30 min bake) run: | python scripts/slo_gate.py \ --service orion-api \ --version "${{ env.VERSION }}" \ --window 30m \ --max-error-rate-delta 0.1 \ --max-p99-latency-delta 50

الخطوة الرابعة: توثيق دليل الإصدار

كل خطوة يجب أن يؤديها إنسان يجب أن تُدوَّن في دليل إجراءات مُعتمَد، لا في ذاكرة أحد. اكتبه كملف RELEASING.md في جذر المستودع. الأقسام الرئيسية لكل نوع مكون:

  • API (CD): دمج PR في main → CI يبني الصورة ويدفعها → ArgoCD/Flux يُرقّيها عبر dev/staging → بوابة canary → الإنتاج الكامل (تلقائي للإصلاحات، موافقة يدوية لـ minor/major).
  • SDK وCLI (قطار شهري): في أول كل شهر، أنشئ فرع release/vX.Y من main. استقِرّ لأسبوع (إصلاحات فقط). ضع وسم vX.Y.0 وادفعه. GoReleaser يعمل تلقائياً عند دفع الوسم.
  • مخطط Helm: حدّث appVersion في Chart.yaml ليتطابق مع إصدار API المُعبَّأ. حدّث version لأي تغييرات على مستوى المخطط. احزم وادفع إلى مستودع ECR OCI.
أتمتة رفع الإصدار باستخدام Conventional Commits و release-please: ثبّت GitHub Action الخاص بـrelease-please في كل مستودع مكون. عند كل دمج في main، يقرأ commits المتفق عليها ويفتح PR للإصدار مع الرفع الصحيح لـ semver وتحديث CHANGELOG.md. دمج هذا الـ PR يُطلق الإصدار. هذا يلغي قرارات الإصدار اليدوية في 90% من الحالات.
# .github/workflows/release-please.yaml — يُضاف لكل مستودع مكون name: release-please on: push: branches: [main] jobs: release-please: runs-on: ubuntu-latest steps: - uses: google-github-actions/release-please-action@v4 id: release with: release-type: go token: ${{ secrets.GITHUB_TOKEN }} - name: Build and push artifact if: ${{ steps.release.outputs.release_created }} env: VERSION: ${{ steps.release.outputs.tag_name }} run: | make build-and-push VERSION=${VERSION}

الخطوة الخامسة: توثيق مصفوفة التوافق

عندما يكون لديك مكونات متعددة بإصدارات مستقلة، يجب أن تنشر مصفوفة توافق حتى يعرف المستخدمون أي الإصدارات تعمل معاً. هذا بالغ الأهمية خاصة لمخطط Helm الذي يحمل إصدار صورة API كـappVersion.

# docs/compatibility.md (كتلة YAML قابلة للقراءة آلياً) # orion-compatibility-matrix: # - cli: "1.9.x" # sdk: "2.1.x" # api: ">=1.4.0, <2.0.0" # helm: "1.4.x" # - cli: "1.8.x" # sdk: "2.0.x" # api: ">=1.3.0, <1.5.0" # helm: "1.3.x" # # CI job: validate-compat يعمل عند كل إصدار للتحقق من تماسك المصفوفة
الخطأ الأكثر شيوعاً في تصميم الإصدار: الفرق تبني pipeline ممتازة لخدمتها الرئيسية وتترك SDK وCLI ومخطط Helm على عمليات يدوية غير رسمية. بعد ستة أشهر يرفع عميل تذكرة P1 لأن CLI v1.7 غير متوافق مع الـ API الذي يُشحن معه، ولا أحد يعرف أي مجموعة إصدارات مدعومة. حدد مصفوفة التوافق من اليوم الأول، قبل أن تحتاجها.

ما يوفره تصميم الإصدار المتكامل

عندما تنتهي من تصميم هذه العملية لمنتجك الخاص، يجب أن تكون قادراً على الإجابة عن كل هذه الأسئلة دون النظر إلى أي لوحة تحكم:

  1. ما الإصدار الحالي لكل مكون في الإنتاج؟
  2. أي commit من Git يعمل في الإنتاج الآن؟
  3. ما الذي تغيّر بين آخر إصدارَين في الإنتاج؟
  4. كيف أتراجع عن orion-api إلى الإصدار التصحيحي السابق دون المساس بـ SDK أو CLI؟
  5. ما مصفوفة الإصدارات المدعومة بين CLI وAPI؟
  6. من وافق على آخر نشر للإنتاج ومتى؟
  7. كيف أُصدر إصلاحاً عاجلاً للإنتاج في غضون 30 دقيقة؟

إذا كانت عملية الإصدار لديك لا تستطيع الإجابة عن الأسئلة السبعة، فهي ناقصة. ابنِ حتى تستطيع.