Blue-Green Deployment: انشر نسخة جديدة بدون ثانية توقف واحدة
هذا المقال موجَّه لمستوى: متوسط. لو بتعمل deploy وانت قلقان إن المستخدمين يشوفوا أخطاء وقت النشر، النمط ده بيخليك تطرح النسخة الجديدة وترجع منها في ثوانٍ لو حصل خطأ.
الخلاصة الأول: مع Blue-Green بتشغّل نسختين متطابقتين من التطبيق، وبتحوّل الترافيك بينهم في خطوة واحدة. المكسب المباشر: نشر بدون downtime، وتراجع (rollback) في ثوانٍ بدل دقائق.
المشكلة باختصار
في النشر التقليدي (rolling أو استبدال مباشر) انت بتلمس البيئة اللي المستخدمين شغّالين عليها دلوقتي. الـ pods القديمة بتموت والجديدة بتقوم، وفي اللحظة دي بتظهر أخطاء 502 و503 لجزء من الطلبات. ولو النسخة الجديدة طلعت فيها باج، الرجوع للنسخة القديمة معناه إعادة بناء ونشر تاني بياخد دقائق — ودقيقة توقف في وقت الذروة معناها طلبات وفلوس ضايعة.
يعني إيه Blue-Green بالظبط
تخيّل مسرح فيه ستارتين: زرقا وخضرا. الجمهور دلوقتي بيتفرّج على المشهد اللي ورا الستارة الزرقا. ورا الكواليس، انت بتجهّز المشهد الجديد كامل ورا الستارة الخضرا وتتأكد إنه تمام من غير ما الجمهور ياخد باله. لما يجهز، بتفتح الخضرا وتقفل الزرقا في لحظة واحدة. لو المشهد الجديد فيه غلط، بترجع تفتح الزرقا فورًا. ده بالظبط اللي بيحصل في Blue-Green.
علميًا: انت بتشغّل بيئتين إنتاجيتين متطابقتين. واحدة (Blue) حيّة وبتستقبل كل الترافيك، والتانية (Green) خاملة. بتنشر الإصدار الجديد على Green، تختبره وهو معزول عن المستخدمين، وبعدين تحوّل موازن الأحمال أو الراوتر من Blue لـ Green. بتفضل Blue شغّالة كما هي عشان تكون تراجعًا فوريًا لو لزم الأمر.
التطبيق العملي: التبديل في Kubernetes
في Kubernetes فيه أنظف طريقة للتبديل: الـ Service بيختار الـ pods بالـ label. بتخلّي الإصدارين شغّالين بنفس الـ app بس بـ version مختلف، وبتبدّل قيمة version في الـ selector. الخطوات:
- اعمل Service بيشاور على
version: blue(النسخة الحيّة). - انشر Deployment جديد بـ
version: greenجنب القديم. - اختبر green داخليًا من غير ما تحوّل ترافيك المستخدمين.
- بدّل الـ selector لـ green — التحويل بيحصل في ثوانٍ.
- لو حصلت مشكلة، رجّع الـ selector لـ blue فورًا.
# web-service.yaml — الـ Service هو "الراوتر" اللي بيوجّه الترافيك
apiVersion: v1
kind: Service
metadata:
name: web
spec:
selector:
app: web
version: blue # بدّلها لـ green وقت التبديل
ports:
- port: 80
targetPort: 8080
# 1) انشر green بجانب blue وتأكد إنها اتظبطت
kubectl apply -f web-green-deployment.yaml
kubectl rollout status deployment/web-green
# 2) اختبار داخلي قبل تحويل الترافيك (من غير مستخدمين)
kubectl port-forward deployment/web-green 8080:8080 &
curl -s localhost:8080/healthz
# 3) التبديل اللحظي: وجّه الـ Service من blue لـ green
kubectl patch service web -p '{"spec":{"selector":{"app":"web","version":"green"}}}'
# 4) لو حصلت مشكلة: تراجع فوري في ثوانٍ
kubectl patch service web -p '{"spec":{"selector":{"app":"web","version":"blue"}}}'
المكاسب والخسائر (الـ trade-off)
خلّينا نحطها على أرض الواقع. متجر إلكتروني بـ 50 ألف زائر/يوم، يعني حوالي 35 طلب/ثانية وقت الذروة. النشر المتدحرج القديم كان بيسبّب ~20 إلى 40 ثانية من أخطاء 502/503 لجزء من الطلبات مع كل deploy. بعد ما اتحوّل لـ Blue-Green، التبديل تمّ في أقل من ثانيتين بصفر أخطاء. ولمّا طلع باج في إصدار، الـ rollback أخذ ~3 ثوانٍ (تبديل selector واحد) مقابل ~5 إلى 8 دقائق لإعادة بناء ونشر النسخة القديمة.
بتكسب: نشر بدون توقف + تراجع شبه لحظي. بتخسر: ضِعف موارد البنية التحتية أثناء فترة النشر، لأن البيئتين بيشتغلوا مع بعض. يعني تكلفة إضافية مؤقتة على الـ CPU والرام. الافتراض هنا إن التطبيق stateless أو حالته مشتركة خارجيًا (قاعدة بيانات أو Redis)، وإن أي تعديل على قاعدة البيانات backward-compatible مع النسختين.
متى لا تستخدم هذه الطريقة
- لو عندك تغيير schema في قاعدة البيانات مش متوافق مع النسخة القديمة، والنسختين بيستخدموا نفس الـ DB — هنا استخدم نمط Expand-Contract بدل ما تعتمد على Blue-Green لوحده.
- لو ميزانية البنية التحتية ضيقة ومش قادر تشغّل ضِعف الموارد ولو مؤقتًا — الـ Rolling أو الـ Canary أوفر في الموارد.
- لو التطبيق بيحتفظ بحالة محلية في الذاكرة (in-memory sessions) من غير مشاركة خارجية — التبديل هيضيّع الجلسات.
- لو عندك آلاف الاتصالات طويلة العمر زي WebSockets — محتاج تدير تصريف الاتصالات (connection draining) قبل ما تقفل Blue.
الخطوة التالية
خطوة واحدة واضحة: لو عندك تطبيق على Kubernetes، اعمل نسخة تانية من الـ Deployment بـ label version: green على بيئة staging، وجرّب أمر kubectl patch service فوق عشان تبدّل الـ selector، وقِس زمن التبديل بنفسك. لو التبديل أخذ أكتر من بضع ثوانٍ، ابعتلي إعداد الـ Service والـ readinessProbe نراجعهم.
المصادر
- Martin Fowler — BlueGreenDeployment: martinfowler.com/bliki/BlueGreenDeployment.html
- Kubernetes Documentation — Service / Labels and Selectors: kubernetes.io/docs/concepts/services-networking/service
- AWS Whitepaper — Blue/Green Deployments on AWS: docs.aws.amazon.com/whitepapers/latest/blue-green-deployments
- Microsoft Azure Architecture Center — Blue-green deployment: learn.microsoft.com/azure/architecture