تطبيقاتي كانت تموت صامتة: كيف أنقذتني ‘الفحوصات الصحية’ في كوبيرنيتيس من جحيم الأعطال غير المتوقعة؟

يا جماعة الخير، السلام عليكم ورحمة الله وبركاته. معكم أخوكم أبو عمر.

خليني أحكيلكم قصة صارت معي قبل كم سنة، قصة علّمتني درس ما بنساه طول ما أنا بشتغل في هالمجال. كانت الساعة حوالي ٢ بعد منتصف الليل، وأنا يا دوب حطيت راسي على المخدة بعد يوم شغل طويل. فجأة، برن التلفون. على الطرف الثاني كان صوت مدير المشروع في شركة من أكبر عملائنا، صوته فيه نبرة هلع ما بتبشّر بالخير أبدًا.

“أبو عمر! الموقع واقع! إلحقنا!”. كان عندهم حملة تخفيضات ضخمة، والموقع هو منصة التجارة الإلكترونية تبعتهم. يعني كل دقيقة والموقع فيها واقع، هي خسارة آلاف الدولارات.

فتحت اللابتوب على السريع وأنا بدعي ربنا يستر. دخلت على لوحة تحكم كوبيرنيتيس (Kubernetes Dashboard). كل شي أخضر! كل الـ “Pods” في حالة Running. ما في أي شي بدل على وجود مشكلة. فتحت سجلات الأخطاء (Logs)، نظيفة وما فيها أي أثر لانهيار أو خطأ فادح. “كيف يعني واقع؟ كل شي مبين تمام عندي!” قلتله وأنا مستغرب.

لكن لما جربت أفتح الموقع بنفسي، الصفحة بتحمّل وبتحمّل… وما بتفتح. التطبيق كان في حالة غريبة، حالة “الزومبي”. هو شغال كعملية (Process) داخل الحاوية (Container)، لكنه ما بستجيب لأي طلبات. كان ميت سريريًا، وكوبيرنيتيس ما عنده فكرة، لأنه بالنسبة إله ما دام العملية شغالة، فالوضع تمام.

بعد بحث وتحفير، اكتشفنا إنه واحد من الخدمات المصغّرة (Microservices) دخل في حالة “جمود” (Deadlock) بسبب مشكلة في الاتصال مع قاعدة البيانات. ما انهار، بس بطل يشتغل. الحل السريع كان إني أحذف الـ Pod يدويًا: kubectl delete pod.... خلال ثواني، كوبيرنيتيس أنشأ واحد جديد، ورجع الموقع يشتغل. لكن هاي كانت زي لما تحط لصقة جروح على كسر. حل مؤقت لمشكلة أكبر بكثير.

هذيك الليلة كانت نقطة التحول. قررت إني لازم أفهم وأطبّق “الفحوصات الصحية” (Health Checks) في كوبيرنيتيس بشكل احترافي. ومن يومها، حياتي كـ DevOps صارت أهدأ بكثير. تعالوا أحكيلكم كيف هالأداة البسيطة ممكن تنقذكم من جحيم الأعطال الصامتة.

ما هي “الفحوصات الصحية” (Health Checks) في كوبيرنيتيس؟ وليش هي مهمة هالقد؟

ببساطة، الفحوصات الصحية هي الطريقة اللي كوبيرنيتيس (اللي بنقدر نعتبره طبيب النظام) بتأكد فيها إنه تطبيقاتك (المرضى) مش بس بتتنفس، لكنها كمان واعية وبصحة جيدة وقادرة على أداء وظيفتها.

بدونها، كوبيرنيتيس بيعرف فقط إذا العملية الأساسية داخل الحاوية تبعتك شغالة أو لأ. لكنه ما بيعرف إذا تطبيقك:

  • عالق في حلقة لا نهائية (Infinite Loop).
  • غير قادر على الاتصال بقاعدة البيانات.
  • استهلك كل الذاكرة وصار بطيء جدًا.
  • بستنى شي معين ليبدأ عمله ولسه مش جاهز.

هاي هي مشكلة “الـ Pod الزومبي” اللي حكيت عنها. الـ Pod بيكون في حالة Running، لكنه فعليًا عديم الفائدة. الفحوصات الصحية هي اللي بتعطي كوبيرنيتيس الذكاء ليتعرف على هاي الحالات ويتصرف بشكل تلقائي، وهذا هو جوهر الأنظمة ذاتية الشفاء (Self-healing Systems).

أنواع الفحوصات الصحية الثلاثة: نبض الحياة، الجهوزية، وبداية التشغيل

كوبيرنيتيس بيوفرلنا ثلاث أنواع من الفحوصات، كل واحد إله هدف مختلف ومهم جدًا نفهم الفرق بينهم.

1. فحص نبض الحياة (Liveness Probe): “هل أنت على قيد الحياة؟”

هذا الفحص بجاوب على سؤال واحد بسيط: “هل التطبيق ما زال يعمل بشكل سليم أم أنه دخل في حالة جمود؟”. إذا فشل هذا الفحص، كوبيرنيتيس بيعتبر إنه الحاوية “ماتت” ولازم يتم إعادة تشغيلها فورًا. هو بمثابة جهاز مراقبة نبضات القلب في المستشفى، إذا توقف النبض، لازم تدخل فوري.

متى تستخدمه؟ استخدمه لاكتشاف الحالات اللي التطبيق فيها بتجمد تمامًا لكنه ما بينهار، مثل حالات الجمود (Deadlocks) أو الحلقات اللانهائية. إذا تطبيقك ممكن يتعافى من هاي الحالة بإعادة التشغيل، فهذا الفحص هو صديقك.

مثال عملي:

تخيل عندك تطبيق ويب، وعملت نقطة نهاية (Endpoint) بسيطة اسمها /healthz بترجع حالة “200 OK” طول ما التطبيق شغال تمام. هيك بنعرّف الفحص في ملف الـ YAML:

apiVersion: v1
kind: Pod
metadata:
  name: my-liveness-app
spec:
  containers:
  - name: app
    image: my-app-image:v1
    ports:
    - containerPort: 8080
    livenessProbe:
      httpGet:
        path: /api/health/live  # المسار اللي لازم كوبيرنيتيس يفحصه
        port: 8080            # البورت اللي التطبيق بيستمع عليه
      initialDelaySeconds: 15 # انتظر 15 ثانية بعد بدء الحاوية قبل أول فحص
      periodSeconds: 20       # اعمل الفحص كل 20 ثانية
      failureThreshold: 3     # اعتبر الفحص فاشل بعد 3 محاولات فاشلة متتالية

نصيحة أبو عمر: يا جماعة، خلوا فحص الحياة بسيط وسريع جدًا. لا تحطوا فيه منطق معقد أو استعلامات من قاعدة البيانات. مجرد فحص بسيط للتأكد إنه خادم الويب بستجيب كافي. إذا الفحص نفسه صار عبء على التطبيق، بتكونوا بتحلوا مشكلة وبتخلقوا عشرة.

2. فحص الجهوزية (Readiness Probe): “هل أنت جاهز لاستقبال الزبائن؟”

هذا الفحص مختلف. هو ما بقتل الحاوية إذا فشل. بدلًا من ذلك، هو بيخبر كوبيرنيتيس إنه “أنا شغال، لكنني لست جاهزًا بعد لاستقبال طلبات جديدة”. لما يفشل هذا الفحص، كوبيرنيتيس بيقوم بإزالة الـ Pod من الخدمة (Service)، وبالتالي ما بيتم توجيه أي مرور (Traffic) إله.

فكر فيها مثل مطعم بفتح الصبح. الأنوار شغالة (Liveness probe ناجح)، لكن الطباخين لسه بحضروا المكونات والأكل مش جاهز. فحص الجهوزية هو اللي بمنع الزبائن من الدخول للمطعم إلا لما يكون كل شي جاهز 100%.

متى تستخدمه؟ هذا الفحص ضروري جدًا في الحالات التالية:

  • عند بدء تشغيل التطبيق، قد يحتاج لوقت لتحميل الإعدادات، أو بناء ذاكرة التخزين المؤقت (Cache)، أو الاتصال بقواعد البيانات.
  • عندما تريد إخراج نسخة من تطبيقك من الخدمة مؤقتًا لعمل صيانة بدون قتلها.
  • لضمان عمليات النشر بدون انقطاع (Zero-downtime deployments).

مثال عملي:

في فحص الجهوزية، ممكن نعمل فحص أعمق شوي، نتأكد مثلًا من الاتصال بقاعدة البيانات.

apiVersion: v1
kind: Pod
metadata:
  name: my-readiness-app
spec:
  containers:
  - name: app
    image: my-app-image:v1
    ports:
    - containerPort: 8080
    readinessProbe:
      httpGet:
        path: /api/health/ready # هاي النقطة ممكن تتأكد من اتصال قاعدة البيانات
        port: 8080
      initialDelaySeconds: 5  # ممكن نبدأ نفحص الجهوزية أسرع
      periodSeconds: 10
      successThreshold: 1     # اعتبره جاهز بعد أول نجاح

نصيحة أبو عمر: هاي الشغلة أنقذتني كثير من مشاكل عمليات النشر (Deployments). لما أعمل تحديث، الـ Pod الجديد ما بستقبل أي طلبات إلا لما ينجح فحص الجهوزية تبعه. هذا يعني إنه المستخدم ما بحس بأي انقطاع في الخدمة نهائيًا. شغل نظيف ومرتب.

3. فحص بداية التشغيل (Startup Probe): “خذ وقتك، بس صحّيني لما تخلص”

هذا الفحص هو إضافة جديدة نسبيًا، وحل مشكلة كانت تؤرق الكثيرين، خصوصًا اللي بيتعاملوا مع تطبيقات قديمة أو تطبيقات بتحتاج وقت طويل جدًا لتبدأ (مثل بعض تطبيقات جافا الضخمة).

المشكلة كانت إنه فحص الحياة (Liveness) ممكن يبدأ شغله قبل ما التطبيق يكون جاهز، فيفشل الفحص، وكوبيرنيتيس يقوم بقتل التطبيق وإعادة تشغيله، وهكذا ندخل في حلقة مفرغة من إعادة التشغيل (CrashLoopBackOff). فحص بداية التشغيل بحل هاي المشكلة. هو بعطّل الفحوصات الثانية (Liveness و Readiness) لحد ما ينجح هو أولًا. بعطي التطبيق “مهلة” كافية ليبدأ على راحته.

متى تستخدمه؟ استخدمه لأي تطبيق يحتاج أكثر من دقيقة أو دقيقتين ليبدأ عمله بشكل كامل.

مثال عملي:

هنا بنعطي التطبيق مهلة طويلة جدًا ليبدأ. إذا فشل فحص البداية بعد 30 محاولة (كل 10 ثواني)، يعني 300 ثانية (5 دقائق)، وقتها فقط كوبيرنيتيس بعتبره فاشل وبعيد تشغيله.

apiVersion: v1
kind: Pod
metadata:
  name: my-startup-app
spec:
  containers:
  - name: app
    image: my-slow-startup-app:v1
    ports:
    - containerPort: 8080
    startupProbe:
      httpGet:
        path: /api/health/startup
        port: 8080
      failureThreshold: 30 # عدد محاولات كبير جدًا
      periodSeconds: 10    # فترة زمنية معقولة بين المحاولات
    # فحوصات الحياة والجهوزية تبدأ فقط بعد نجاح فحص البداية
    livenessProbe:
      httpGet:
        path: /api/health/live
        port: 8080
      periodSeconds: 20

نصيحة أبو عمر: قبل ما يطلع الـ Startup Probe، كنا بنتحايل على النظام بزيادة الـ `initialDelaySeconds` في فحص الحياة لقيم كبيرة جدًا. كانت طريقة مش عملية وبتسبب مشاكل. هسا مع الـ Startup Probe، الوضع صار أرتب وأوضح بكثير. استخدموها للتطبيقات البطيئة وما تستحوا.

كيفية تنفيذ الفحوصات: مش بس HTTP

كوبيرنيتيس مرن جدًا وبيعطيك ثلاث طرق لتنفيذ الفحص:

  1. HTTP GET: الأكثر شيوعًا. يرسل طلب GET لمسار معين ويتوقع رمز استجابة بين 200-399.
  2. TCP Socket: يحاول فتح اتصال TCP على منفذ معين. مفيد جدًا للخدمات التي لا تستخدم بروتوكول HTTP، مثل قواعد البيانات أو خوادم الرسائل (Message Brokers).
  3. Exec Command: ينفذ أمرًا معينًا داخل الحاوية. يعتبر الفحص ناجحًا إذا كان رمز الخروج (Exit Code) للأمر هو 0. هذا الخيار يعطيك قوة ومرونة هائلة، حيث يمكنك كتابة أي سكريبت أو أمر للتحقق من صحة التطبيق.

مثال على فحص TCP و Exec:

# مثال على فحص TCP لقاعدة بيانات PostgreSQL
livenessProbe:
  tcpSocket:
    port: 5432 # منفذ PostgreSQL الافتراضي
  initialDelaySeconds: 15
  periodSeconds: 20

# مثال على فحص Exec للتحقق من وجود ملف معين
readinessProbe:
  exec:
    command:
    - cat
    - /tmp/app-ready # التطبيق يقوم بإنشاء هذا الملف عندما يكون جاهزًا
  initialDelaySeconds: 5
  periodSeconds: 5

نصائح أبو عمر الذهبية لإعداد فحوصات صحية لا تُقهر

بعد سنين من التجارب والوقوع في الأخطاء، جمعتلكم هاي النصائح العملية:

  • حافظ على بساطة وسرعة الفحوصات: نقطة النهاية (Endpoint) الخاصة بالفحص يجب أن تكون الأسرع في تطبيقك. لا تضع فيها أي منطق معقد.
  • افصل بين مسؤوليات الفحوصات: فحص الحياة (Liveness) يجب أن يتحقق فقط من أن التطبيق “حي”. فحص الجهوزية (Readiness) يجب أن يتحقق من أن التطبيق “قادر على خدمة الطلبات” (متصل بقاعدة البيانات، الكاش جاهز، إلخ). يمكن للتطبيق أن يكون حيًا ولكنه غير جاهز.
  • لا تجعل الفحص يعتمد على خدمات خارجية: فحص صحة خدمة (أ) يجب ألا يفشل لأن خدمة (ب) لا تعمل. يجب أن يعكس صحة خدمة (أ) فقط.
  • اضبط المؤقتات بعناية:
    • initialDelaySeconds: أعطِ تطبيقك وقتًا كافيًا ليبدأ.
    • periodSeconds: لا تجعلها قصيرة جدًا فتسبب ضغطًا على تطبيقك.
    • timeoutSeconds: يجب أن تكون قيمته قصيرة. إذا لم يرد الفحص خلال ثانية أو ثانيتين، فهناك مشكلة.
    • failureThreshold: لا تجعل قيمته 1 لفحص الحياة، فقد يتسبب ذلك في إعادة تشغيل غير ضرورية بسبب مشكلة مؤقتة في الشبكة. قيمة 3 غالبًا ما تكون بداية جيدة.
  • سجّل نتائج الفحوصات (Logging): عندما يفشل فحص الجهوزية، اجعل نقطة النهاية تسجل سبب الفشل في الـ logs. “فحص الجهوزية فشل” رسالة غير مفيدة. “فحص الجهوزية فشل: لا يمكن الاتصال بقاعدة بيانات Redis” هي رسالة ممتازة تساعد في التشخيص.

الخلاصة: من الإطفائي إلى المهندس المعماري 🏗️

في بداية مسيرتي مع كوبيرنيتيس، كنت أقضي الكثير من الوقت في دور “الإطفائي”. أستيقظ على مكالمات طارئة، وأقوم بإعادة تشغيل الأشياء يدويًا، وأتعامل مع المشاكل بعد وقوعها.

الفحوصات الصحية كانت من أهم الأدوات التي نقلتني من هذا الدور إلى دور “المهندس المعماري”. بدلًا من إطفاء الحرائق، أصبحت أصمم أنظمة قادرة على تحمل الأعطال والشفاء منها ذاتيًا. هذا هو الفرق بين مجرد استخدام كوبيرنيتيس، وبين استخدامه بالطريقة الصحيحة لبناء بنية تحتية قوية ومرنة.

يا صديقي المطور، ويا صديقي مهندس الـ DevOps، لا تنتظر الكارثة حتى تتعلم الدرس. ابدأ اليوم. افتح ملفات الـ YAML الخاصة بتطبيقاتك وتأكد من وجود فحوصات صحية فعالة. قد تكون هي الشيء الوحيد الذي يقف بينك وبين مكالمة هاتفية مرعبة في منتصف الليل.

خلي شغلك يحكي عنك، وخلي أنظمتك تشفي حالها بحالها. بالتوفيق! 🚀

أبو عمر

سجل دخولك لعمل نقاش تفاعلي

كافة المحادثات خاصة ولا يتم عرضها على الموقع نهائياً

آراء من النقاشات

لا توجد آراء منشورة بعد. كن أول من يشارك رأيه!

آخر المدونات

أدوات وانتاجية

ذاكرتي كانت أسوأ من السمكة الذهبية: كيف أنقذتني ‘أسماء الأوامر المستعارة’ (Aliases) من جحيم إعادة كتابة الأوامر الطويلة؟

أشارككم تجربتي الشخصية كـ "أبو عمر" مع ذاكرتي الضعيفة في حفظ الأوامر الطويلة، وكيف أصبحت "أسماء الأوامر المستعارة" (Aliases) في سطر الأوامر سلاحي السري لزيادة...

9 أبريل، 2026 قراءة المزيد
نصائح برمجية

شروط الـ if المتداخلة كانت كابوسًا: كيف أنقذتني ‘شروط الحماية’ (Guard Clauses) من جحيم الشيفرة السهمية؟

أنا أبو عمر، وأذكر جيدًا الليالي التي قضيتها تائهًا في شيفرة تشبه "السهم" بسبب شروط if المتداخلة. في هذه المقالة، أشارككم كيف أنقذتني تقنية بسيطة...

9 أبريل، 2026 قراءة المزيد
تجربة المستخدم والابداع البصري

واجهاتنا كانت تستبعد المستخدمين: كيف أنقذتنا ‘معايير الوصول الرقمي (WCAG)’ من جحيم التجربة السيئة والشكاوى القانونية؟

أذكر ذلك الصباح جيدًا، حين وصل بريد إلكتروني من أحد عملائنا الكبار، لم يكن استفسارًا عاديًا، بل كان يحمل في طياته لهجة قانونية صارمة. كانت...

9 أبريل، 2026 قراءة المزيد
البودكاست