Kubernetes Probes بالعربي: امنع الـ Restarts الكاذبة
مستوى القارئ: متوسط
هتخرج من المقال ده بإعداد Kubernetes probes عملي يقلل الـ restarts الكاذبة، ويفصل بين مشكلة البداية ومشكلة استقبال الترافيك ومشكلة التعليق الحقيقي.
المشكلة باختصار
الطريقة الشائعة الغلط إنك تحط endpoint واحد اسمه /health وتستخدمه في livenessProbe وreadinessProbe بنفس القيم. الطريقة دي بتفشل لما التطبيق يتأخر في الـ warmup أو لما قاعدة البيانات تبقى بطيئة 20 ثانية. Kubernetes يفتكر إن التطبيق مات، فيعمل restart، والـ restart يزود الضغط بدل ما يحله.
الافتراض هنا إن عندك خدمة HTTP داخل Kubernetes، بتحتاج 60 إلى 180 ثانية أحيانًا عشان تعمل migration خفيفة أو تسخن cache. لو عندك 10 replicas وكل replica بيتقتل مرتين أثناء النشر، أنت ضيعت تقريبًا 20 دورة startup بدون سبب.
افصل بين الثلاث إشارات
ركز في الفرق. startupProbe بتقول: هل التطبيق خلص بداية؟ لو فشلت، Kubernetes ينتظر ولا يشغل liveness لسه. readinessProbe بتقول: هل الـ Pod جاهز يستقبل traffic؟ لو فشلت، الـ Pod يخرج من Service endpoints لكنه يفضل شغال. livenessProbe بتقول: هل التطبيق علق لدرجة إن restart هو القرار الصحيح؟ لو فشلت مرات متتالية، kubelet يعمل restart للحاوية.
مثال بسيط: مطعم لسه بيفتح. startupProbe معناها: هل المطبخ اتجهز؟ readinessProbe معناها: هل نستقبل طلبات دلوقتي؟ livenessProbe معناها: هل العامل الرئيسي اختفى تمامًا ولازم نعيد تشغيل الشيفت؟ نفس المثال بعد كده يتحول تقنيًا: البداية غير الجاهزية، والجاهزية غير الحياة.
إعداد عملي قابل للنسخ
أفضل طريقة إنك تستخدم endpoints منفصلة. /livez لا يفحص قاعدة البيانات. يفحص إن process شغال ومش deadlocked. /readyz يفحص الاتصالات المهمة لاستقبال request حقيقي، زي DB pool أو queue. وstartupProbe يدي التطبيق مساحة بداية محسوبة.
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
replicas: 3
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: ghcr.io/example/api:1.8.0
ports:
- containerPort: 8080
startupProbe:
httpGet:
path: /livez
port: 8080
periodSeconds: 10
failureThreshold: 30
timeoutSeconds: 2
readinessProbe:
httpGet:
path: /readyz
port: 8080
periodSeconds: 5
failureThreshold: 3
timeoutSeconds: 2
livenessProbe:
httpGet:
path: /livez
port: 8080
periodSeconds: 10
failureThreshold: 3
timeoutSeconds: 2بالظبط، failureThreshold: 30 مع periodSeconds: 10 في startup تعني نافذة بداية تصل إلى 300 ثانية. ده مناسب لو أسوأ startup عندك 180 ثانية. المكسب إنك تمنع restart مبكر. التكلفة إن التطبيق المعطل فعلاً ممكن يقعد لحد 5 دقائق قبل ما Kubernetes يعتبره فشل في البداية.
سيناريو واقعي بالأرقام
لو عندك موقع بـ 50K زائر يوميًا، ومتوسط النشر بيحصل مرتين في اليوم، وكل نشر بيعمل 6 restarts كاذبة بسبب liveness شديد، ممكن تشوف 12 موجة 502 قصيرة يوميًا. لو كل موجة 15 ثانية، أنت بتجمع 3 دقائق تدهور يومي غير ضروري. بعد فصل probes، الهدف الواقعي إنك تنزل restarts الكاذبة من 6 إلى 0 في النشر الواحد، وتخلي readiness هي اللي توقف الترافيك مؤقتًا بدل قتل الحاوية.
لقياس النتيجة، راقب kubectl describe pod للأحداث، وعدد Restart Count قبل وبعد. لو كان المتوسط 4 restarts لكل replica أثناء deploy، وبعد التعديل بقى 0 أو 1، التعديل نجح. لو لسه الرقم عالي، المشكلة مش في probes فقط؛ راجع logs وCPU throttling.
kubectl get pods -l app=api
kubectl describe pod api-xxxxx | sed -n '/Events:/,$p'
kubectl get pod api-xxxxx -o jsonpath='{.status.containerStatuses[0].restartCount}'الـ trade-off هنا
استخدام startupProbe يكسبك حماية من القتل المبكر، لكنه يطيل اكتشاف التطبيق الذي لا يبدأ أصلًا. استخدام readinessProbe مع فحص DB يكسبك traffic routing أدق، لكنه ممكن يخرج كل الـ Pods من الخدمة لو قاعدة البيانات عندها spike عام. استخدام livenessProbe الخفيف يكسبك restart عند deadlock، لكنه لن يصلح بطء dependencies.
بدل ما تزود failureThreshold عشوائيًا، اربطه بقياس. لو P95 للـ startup عندك 75 ثانية، خلي نافذة startup حوالي 120 ثانية. لو P99 عندك 220 ثانية، استخدم 300 ثانية. لا تجعلها 15 دقيقة إلا لو عندك سبب واضح، لأنك كده بتأخر اكتشاف الفشل الحقيقي.
متى لا تستخدم هذه الطريقة
لا تستخدم readiness لفحص dependency غير ضرورية لكل request. لو خدمة recommendation وقعت لكن checkout يشتغل عادي، readiness لا يجب أن تفشل بسبب recommendation. ولا تستخدم liveness لفحص قاعدة البيانات؛ بطء DB لا يعني إن العملية ماتت. كمان لو التطبيق CLI job قصير داخل Kubernetes Job، غالبًا probes مش أولوية إلا لو الـ job طويل جدًا.
مصادر اعتمد عليها
- Kubernetes Docs: Liveness, Readiness, and Startup Probes
- Kubernetes Docs: Configure Liveness, Readiness and Startup Probes
- Kubernetes Docs: Pod Lifecycle
الخطوة التالية
افتح Deployment واحد عندك، وافصل /livez عن /readyz، ثم أضف startupProbe بنافذة تساوي P99 startup زائد 30%. بعد أول deploy، قارن Restart Count قبل وبعد.