سير العمل لنشر الإنتاج

استراتيجيات النشر الآمن

5 دقيقة للقراءة

لماذا تهم عمليات النشر التدريجية

الكود المُنشأ بالذكاء الاصطناعي، رغم اختباره، قد يتصرف بشكل مختلف في الإنتاج:

  • حالات حافة غير مغطاة في الاختبارات
  • مشاكل متعلقة بالنطاق
  • التكامل مع خدمات الإنتاج
  • أنماط سلوك المستخدم الحقيقي

النشر التدريجي يقلل نطاق الضرر ويمكّن من التعافي السريع.

نشر الكناري

إعداد إصدارات الكناري

# kubernetes/canary-deployment.yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: api-rollout
spec:
  replicas: 10
  strategy:
    canary:
      steps:
        - setWeight: 5      # 5% من الحركة
        - pause: {duration: 5m}
        - setWeight: 25     # 25% من الحركة
        - pause: {duration: 10m}
        - setWeight: 50     # 50% من الحركة
        - pause: {duration: 15m}
        - setWeight: 100    # نشر كامل
      analysis:
        templates:
          - templateName: success-rate
          - templateName: latency
        startingStep: 1  # بدء التحليل عند خطوة الكناري الأولى

تحليل الكناري الآلي

# kubernetes/analysis-template.yaml
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
  name: success-rate
spec:
  metrics:
    - name: success-rate
      interval: 1m
      successCondition: result >= 0.99
      failureLimit: 3
      provider:
        prometheus:
          address: http://prometheus:9090
          query: |
            sum(rate(http_requests_total{status=~"2.*"}[5m])) /
            sum(rate(http_requests_total[5m]))

    - name: latency-p99
      interval: 1m
      successCondition: result <= 500
      failureLimit: 3
      provider:
        prometheus:
          query: |
            histogram_quantile(0.99,
              rate(http_request_duration_seconds_bucket[5m]))
            * 1000

أعلام الميزات

تنفيذ أعلام الميزات

// lib/feature-flags.ts
import { LaunchDarkly } from 'launchdarkly-node-server-sdk';

const ldClient = LaunchDarkly.init(process.env.LD_SDK_KEY);

export async function isFeatureEnabled(
  flagKey: string,
  user: User,
  defaultValue: boolean = false
): Promise<boolean> {
  const ldUser = {
    key: user.id,
    email: user.email,
    custom: {
      plan: user.plan,
      createdAt: user.createdAt.toISOString()
    }
  };

  return ldClient.variation(flagKey, ldUser, defaultValue);
}

// الاستخدام
async function processOrder(order: Order, user: User) {
  const useNewPaymentFlow = await isFeatureEnabled(
    'new-payment-flow',
    user
  );

  if (useNewPaymentFlow) {
    return newPaymentProcessor.process(order);
  }
  return legacyPaymentProcessor.process(order);
}

النشر التدريجي مع الأعلام

claude "أنشئ خطة نشر علم ميزة لتدفق
الدفع الجديد لدينا. ضمّن:
1. مرحلة الاختبار الداخلي
2. مرحلة مستخدمي بيتا
3. النشر القائم على النسبة المئوية
4. الإصدار الكامل
5. محفزات التراجع"
## خطة نشر تدفق الدفع الجديد

### المرحلة 1: الاختبار الداخلي (اليوم 1-3)
- العلم: `new-checkout-flow`
- الهدف: الموظفون الداخليون فقط
- المقاييس: معدل الخطأ، معدل الإكمال
- معايير النجاح: معدل الخطأ < 0.1%

### المرحلة 2: مستخدمو بيتا (اليوم 4-7)
- الهدف: المستخدمون مع `beta_tester: true`
- المستخدمون المتوقعون: ~500
- المقاييس: معدل التحويل، تذاكر الدعم
- معايير النجاح: لا تراجع في التحويل

### المرحلة 3: النشر بالنسبة المئوية (اليوم 8-14)
- اليوم 8: 5% من المستخدمين
- اليوم 10: 25% من المستخدمين
- اليوم 12: 50% من المستخدمين
- اليوم 14: 75% من المستخدمين
- المراقبة: جميع KPIs مقابل مجموعة التحكم

### المرحلة 4: الإصدار الكامل (اليوم 15)
- 100% من المستخدمين
- أزل العلم بعد أسبوعين استقرار

### محفزات التراجع (آلي)
- معدل الخطأ > 1%
- زمن انتقال p99 > 2000ms
- انخفاض معدل التحويل > 5%

النشر الأزرق-الأخضر

إعداد البنية التحتية

# kubernetes/blue-green.yaml
apiVersion: v1
kind: Service
metadata:
  name: app-production
spec:
  selector:
    app: myapp
    version: blue  # بدّل إلى 'green' للنشر
  ports:
    - port: 80
      targetPort: 3000

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-blue
spec:
  replicas: 5
  selector:
    matchLabels:
      app: myapp
      version: blue
  template:
    spec:
      containers:
        - name: app
          image: myapp:v1.0.0

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-green
spec:
  replicas: 5
  selector:
    matchLabels:
      app: myapp
      version: green
  template:
    spec:
      containers:
        - name: app
          image: myapp:v1.1.0  # الإصدار الجديد

سكريبت النشر

#!/bin/bash
# scripts/blue-green-deploy.sh

NEW_VERSION=$1
CURRENT=$(kubectl get svc app-production -o jsonpath='{.spec.selector.version}')
TARGET=$([ "$CURRENT" == "blue" ] && echo "green" || echo "blue")

echo "نشر $NEW_VERSION إلى بيئة $TARGET..."

# تحديث نشر الهدف
kubectl set image deployment/app-$TARGET app=myapp:$NEW_VERSION

# انتظر النشر
kubectl rollout status deployment/app-$TARGET

# شغّل اختبارات الدخان
./scripts/smoke-tests.sh app-$TARGET
if [ $? -ne 0 ]; then
  echo "فشلت اختبارات الدخان، إلغاء النشر"
  exit 1
fi

# بدّل الحركة
kubectl patch svc app-production \
  -p "{\"spec\":{\"selector\":{\"version\":\"$TARGET\"}}}"

echo "اكتمل النشر. الحركة الآن تُوجه إلى $TARGET"
echo "أمر التراجع: kubectl patch svc app-production -p '{\"spec\":{\"selector\":{\"version\":\"$CURRENT\"}}}'"

التسليم التدريجي مع مراقبة الذكاء الاصطناعي

claude "راقب هذا النشر ونبّه إذا:
1. معدل الخطأ يتجاوز الأساس بـ 50%
2. زمن انتقال p95 يتجاوز 500ms
3. استخدام الذاكرة ينمو بشكل غير طبيعي
4. أنواع أخطاء جديدة تظهر في السجلات

الأساس الحالي:
- معدل الخطأ: 0.1%
- زمن انتقال p95: 250ms
- الذاكرة: 512MB مستقرة"
// monitoring/deployment-watcher.ts
interface DeploymentMetrics {
  errorRate: number;
  p95Latency: number;
  memoryUsage: number;
  errorTypes: Set<string>;
}

async function monitorDeployment(
  deploymentId: string,
  baseline: DeploymentMetrics
): Promise<void> {
  const alertThresholds = {
    errorRateIncrease: 0.5,  // 50% فوق الأساس
    p95LatencyMax: 500,      // ms
    memoryGrowthRate: 0.1,   // 10% في الساعة
  };

  const interval = setInterval(async () => {
    const current = await getMetrics(deploymentId);

    // تحقق من معدل الخطأ
    if (current.errorRate > baseline.errorRate * 1.5) {
      await triggerAlert({
        severity: 'high',
        message: `معدل الخطأ ${current.errorRate}% يتجاوز الحد`,
        action: 'فكر في التراجع'
      });
    }

    // تحقق من زمن الانتقال
    if (current.p95Latency > alertThresholds.p95LatencyMax) {
      await triggerAlert({
        severity: 'medium',
        message: `زمن انتقال p95 ${current.p95Latency}ms يتجاوز 500ms`,
        action: 'تحقق من النقاط النهائية البطيئة'
      });
    }

    // تحقق من أنواع الأخطاء الجديدة
    const newErrors = difference(current.errorTypes, baseline.errorTypes);
    if (newErrors.size > 0) {
      await triggerAlert({
        severity: 'high',
        message: `أنواع أخطاء جديدة مكتشفة: ${[...newErrors].join(', ')}`,
        action: 'راجع سجلات الأخطاء'
      });
    }
  }, 60000); // تحقق كل دقيقة
}

أتمتة التراجع

# .github/workflows/auto-rollback.yml
name: Auto Rollback

on:
  workflow_dispatch:
    inputs:
      reason:
        description: 'سبب التراجع'
        required: true

jobs:
  rollback:
    runs-on: ubuntu-latest
    steps:
      - name: الحصول على الإصدار السابق
        id: prev
        run: |
          PREV=$(kubectl rollout history deployment/app -o jsonpath='{.metadata.annotations.previous-version}')
          echo "version=$PREV" >> $GITHUB_OUTPUT

      - name: تنفيذ التراجع
        run: |
          kubectl rollout undo deployment/app
          kubectl rollout status deployment/app

      - name: إبلاغ الفريق
        uses: slackapi/slack-github-action@v1
        with:
          payload: |
            {
              "text": "🔄 تم تنفيذ التراجع",
              "blocks": [
                {
                  "type": "section",
                  "text": {
                    "type": "mrkdwn",
                    "text": "*اكتمل التراجع*\nالسبب: ${{ inputs.reason }}\nالتراجع إلى: ${{ steps.prev.outputs.version }}"
                  }
                }
              ]
            }

الدرس التالي

سنغطي مراقبة الإنتاج والاستجابة للحوادث للكود المُنشأ بالذكاء الاصطناعي. :::

اختبار

الوحدة 5: سير العمل لنشر الإنتاج

خذ الاختبار