سير العمل لنشر الإنتاج
استراتيجيات النشر الآمن
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 }}"
}
}
]
}
الدرس التالي
سنغطي مراقبة الإنتاج والاستجابة للحوادث للكود المُنشأ بالذكاء الاصطناعي. :::