المستوى: محترف
Argo Rollouts: Canary Deployment يكتشف الباگ قبل العميل
لو فريقك بيـ deploy على Kubernetes بـ kubectl apply أو RollingUpdate العادي، أول pod جديد بياخد ترافيك حقيقي من المستخدم في ثوانٍ. لو فيه regression في الإصدار الجديد، الكشف بيتأخر دقايق وممكن تخسر آلاف الـ requests قبل ما الـ rollback يحصل يدوياً. Argo Rollouts بيغيّر اللعبة: بيوجّه 5% بس من الترافيك للإصدار الجديد، يقيس error rate و latency من Prometheus، ولو فيه انحراف بيرجع تلقائياً للإصدار القديم في أقل من دقيقة.
المشكلة باختصار
Kubernetes RollingUpdate بيستبدل الـ pods القديمة بالجديدة على دفعات بافتراض إن الإصدار الجديد سليم. لكن في الإنتاج، نسبة معتبرة من الـ deployments بيطلع فيها regression — حسب State of DevOps Report 2024، الفرق بين الفرق العالية والمنخفضة الأداء بيظهر في Change Failure Rate قبل أي حاجة تانية.
لو عندك تطبيق بيخدم 8000 request في الدقيقة و RollingUpdate بياخد 3 دقايق، أنت بتعرّض ~24,000 request لباگ محتمل قبل ما الـ rollback اليدوي يحصل. ده مش "أمان"، ده مقامرة على إن المستخدم ما يكتشفش الباگ قبلك.
مثال للمبتدئ علشان نفهم الفكرة
تخيّل مطعم بيغيّر صلصة الباستا. الطريقة العادية: بيقدّموا الصلصة الجديدة لكل العملاء فوراً. لو طلعت مالحة، 200 طبق بيتباع قبل ما الـ chef ياكل واحد ويكتشف. Canary deployment زي إن الـ chef يدوق الصلصة هو الأول، بعدين يقدّمها لـ 5 عملاء، بعدين 20، بعدين الكل. لو طلعت فيها مشكلة في أي مرحلة، بيرجع للصلصة القديمة قبل ما الباقي يجرّبها.
التعريف العلمي: Canary Deployment هي استراتيجية progressive delivery بتوجّه نسبة محدودة من production traffic لإصدار جديد، تقيس indicators معرّفة (error rate, latency, business metrics)، وبتقرر تلقائياً إكمال الـ rollout أو الرجوع بناءً على تحليل إحصائي. الاسم جاي من "canary in a coal mine" — العصفور اللي كان بيموت قبل عمال المنجم لو الهوا فيه غاز.
ليه RollingUpdate العادي مش كفاية
RollingUpdate بيحل مشكلة zero-downtime، لكن مش بيحل مشكلة detection. الـ readiness probe بتشيك إن الـ pod بيرد على HTTP، مش إن الإصدار الجديد بيرد بنفس الجودة. ركز على النقطة دي: pod ممكن يكون Ready و response time عنده 4x الإصدار القديم وerror rate 6%. RollingUpdate ميشوفش الفرق ده — هو بس بيشيك إن الـ liveness و readiness بيرجعوا 200.
الافتراض إن الـ unit tests و integration tests كافية لاكتشاف كل المشاكل قبل الإنتاج. ده افتراض غلط لأي تطبيق حقيقي: latency regressions، memory leaks بطيئة، behavior تحت traffic عالي، تفاعل مع cache بارد — كل ده ميتلقاش في staging.
Argo Rollouts: الـ controller اللي بياخد القرار من metrics
Argo Rollouts بيستبدل Deployment resource بـ Rollout. ده CRD بيتحكم في حركة الترافيك بـ steps واضحة، وكل step ممكن يستدعي AnalysisTemplate يقيس indicators من Prometheus, Datadog, CloudWatch أو حتى Web requests، ويقرر يكمل أو يعمل rollback.
مثال تنفيذي: Rollout بـ steps متدرجة
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: payments-api
spec:
replicas: 10
strategy:
canary:
canaryService: payments-canary
stableService: payments-stable
trafficRouting:
istio:
virtualService:
name: payments-vs
routes:
- primary
steps:
- setWeight: 5
- pause: { duration: 2m }
- analysis:
templates:
- templateName: error-rate-check
- setWeight: 25
- pause: { duration: 5m }
- setWeight: 50
- pause: { duration: 10m }
- setWeight: 100
selector:
matchLabels:
app: payments-api
template:
metadata:
labels:
app: payments-api
spec:
containers:
- name: api
image: payments-api:v2.4.1
ports:
- containerPort: 8080
الترتيب هنا مش عشوائي. أول step بـ 5% بياخد عينة كبيرة كفاية لاكتشاف الـ errors الواضحة بدون تعريض شريحة كبيرة. الـ pause لمدة دقيقتين بيدّي وقت لمتريكس Prometheus تتجمع. الـ analysis في الـ step التالت بيقرر يكمل أو يرجع.
AnalysisTemplate: السؤال اللي بيتسأل لـ Prometheus
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: error-rate-check
spec:
metrics:
- name: error-rate
interval: 30s
count: 4
successCondition: result[0] <= 0.01
failureLimit: 2
provider:
prometheus:
address: http://prometheus.monitoring.svc:9090
query: |
sum(rate(http_requests_total{
service="payments-canary",
status=~"5.."
}[2m]))
/
sum(rate(http_requests_total{
service="payments-canary"
}[2m]))
الـ analysis ده بيشيك كل 30 ثانية على نسبة 5xx errors في الـ canary لمدة دقيقتين (4 قياسات). لو عدّت 1% في قياسين متتاليين (failureLimit: 2)، Argo Rollouts بيعمل rollback تلقائي ويرجع كل الترافيك للإصدار القديم. الـ successCondition بيستخدم expression بسيط — تقدر تضيف P95 latency أو business metrics بنفس الشكل.
Trade-offs الحقيقية: بتكسب X، بتدفع Y
- المكسب: Mean Time to Detection لـ regression بينزّل من ~12 دقيقة (يدوي بعد شكوى المستخدم) إلى أقل من دقيقتين (تلقائي من المتريكس).
- التكلفة الأولى: محتاج Service Mesh (Istio أو Linkerd) عشان traffic splitting يحصل بدقة على مستوى الـ HTTP request. لو معندكش، Argo Rollouts بيستخدم replica-based splitting وده بيدي تقريب 10% بدل 5% بالظبط.
- التكلفة التانية: الـ deploy الواحد بياخد وقت أطول. Rollout كامل بـ 4 خطوات وanalysis ممكن ياخد 30-45 دقيقة بدل 3 دقايق. لو فيه hotfix أمني عاجل، استخدم blueGreen أو bypass الـ analysis steps يدوياً بـ
kubectl argo rollouts promote. - التكلفة التالتة: AnalysisTemplate محتاج indicators ناضجة. لو Prometheus عندك مش بيرصد الـ business-level metrics مظبوطة (error rate per endpoint, conversion rate)، الـ canary هيوافق على إصدارات سيئة لأنها بترد 200 OK بمحتوى غلط.
متى لا تستخدم Argo Rollouts
متستخدمهوش لو الفريق عنده أقل من 3 services في الإنتاج أو الترافيك تحت 100 RPS. الـ overhead الإداري والـ Service Mesh مش هيدفعوا تكلفتهم على scale صغير. الـ overhead بيشمل: تشغيل وتحديث الـ controller، صيانة AnalysisTemplates، وإدارة الـ Service Mesh نفسه.
كمان متستخدمهوش لـ stateful workloads زي databases أو queues. الـ canary مفهوم اتبنى لـ stateless HTTP services — Pod جديد لـ DB ميقدرش يخدم 5% من القراءات بنفس الـ consistency بدون تعقيدات replication. لو محتاج progressive rollout للـ schema changes، استخدم expand-and-contract migrations مش canary.
أرقام من إنتاج فعلي
على cluster Kubernetes بـ 28 microservice و 6500 RPS متوسط، بعد 6 شهور من تحويل كل deployments من RollingUpdate لـ Rollout:
- Failed deployments بسبب regression: من 8% إلى 0.7%
- MTTR للـ rollback: من 14 دقيقة (يدوي بعد إشعار من PagerDuty) إلى 47 ثانية (تلقائي من analysis)
- Requests معرّضة لـ regression في كل deploy: من ~24,000 إلى ~1,200
- الزمن الإضافي لكل deploy: +28 دقيقة في المتوسط
الافتراض إن عندك Prometheus بـ retention 15 يوم على الأقل، Service Mesh بيدعم header-based routing، و SLOs معرّفة لكل service. الأرقام دي تقديرية ومرتبطة بهذا الـ workload المحدد، مش وعد عام.
الخطوة التالية
افتح أبسط microservice عندك في staging واستبدل الـ Deployment بـ Rollout بنفس الـ pod template. ابدأ بـ steps بسيطة جداً: setWeight: 20, pause: 5m, setWeight: 100، بدون analysis. لما تتأكد إن traffic splitting شغّال صح، ضيف AnalysisTemplate على error rate بس. متضيفش business metrics في أول إعداد — هيعقّد الـ debugging ومش هتعرف هل الـ rollback السبب technical ولا حقيقي.