التحجيم التلقائي للكتلة وKarpenter
التحجيم التلقائي للكتلة وKarpenter
التحجيم الأفقي للحاويات (HPA) يُوسّع أحمال العمل؛ أما التحجيم التلقائي للكتلة فيُوسّع البنية التحتية ذاتها. حين تمتلئ كل العقد ولا يستطيع Pod جديد الجدولة، تحتاج إلى ظهور طاقة استيعابية بسرعة وبتكلفة مناسبة وبالحجم الصحيح. إتقان هذا الأمر هو الفارق بين منصة تستوعب ارتفاعات حركة المرور بسلاسة وأخرى تُنبّهك الساعة الثالثة صباحاً لأن Pods ظلت في حالة Pending لعشرين دقيقة.
يتناول هذا الدرس جيلين من الفكرة ذاتها: Cluster Autoscaler (CA)، الأداة الكلاسيكية لمشروع Kubernetes، وKarpenter، البديل الحديث المنشأ من AWS (والمنضم الآن إلى CNCF) الذي يُعالج معظم القيود البنيوية في CA.
لماذا تنفد موارد العقد: مشكلة تعبئة الصناديق
تجدول Kubernetes الـ Pods على العقد باستخدام استراتيجية bin-packing: تضع أكبر عدد ممكن من الـ Pods في الطاقة المتاحة. كل Pod يُعلن عن requests (الحد الأدنى المضمون من CPU/الذاكرة) وlimits (السقف الصارم). يجمع المجدول الـ requests لكل عقدة ولن يضع Pod إذا كان سيتجاوز الطاقة الاستيعابية المُخصّصة للعقدة.
في الواقع العملي، لا تُستخدَم العقد بنسبة 100%: عفاريت النظام (kubelet وkube-proxy وعوامل السجلات وإضافات CNI) تستهلك 5–15% من طاقة كل عقدة قبل أن تبدأ أحمال العمل. عقدة بأربعة vCPUs تُتيح عادةً نحو 3.5 vCPU كطاقة قابلة للتخصيص. هذا الفارق يعني أنك دائماً تحتاج عقدًا أكثر مما تقترح الحسابات الخام.
kubectl describe node <name> وانظر إلى كتلة Allocatable — هذا هو الرقم الذي يستخدمه المجدول. الفارق بين Capacity وAllocatable محجوز لنظام التشغيل ومكونات نظام Kubernetes.
Cluster Autoscaler (CA) — الأسلوب الكلاسيكي
يراقب CA الـ Pods في حالة Pending ويتحقق مما إذا كانت إضافة عقدة من أي Node Group مُهيّأ (ASGs في AWS، أو Managed Instance Groups في GKE، أو VMSS في Azure) ستجعل الـ Pod قابلاً للجدولة. إذا كان الجواب نعم، يرفع العداد المطلوب للمجموعة. كذلك يفحص العقد غير المُستخدمة، وبعد نافذة خمول قابلة للضبط (10 دقائق افتراضياً)، يُخلّيها ويُنهيها.
القيود الرئيسية لـ CA:
- التفكير المرتبط بـ ASG: يعمل CA على أنواع instance محددة مسبقاً داخل كل ASG. يجب إنشاء ASG لكل عائلة instance — خلط أنواع instances يتطلب مجموعات متعددة وضبطاً دقيقاً للأولويات.
- بطء التوسعة: يستطلع CA كل 10 ثوانٍ، ثم ينتظر مزوّد السحابة لتوفير عقدة (1–3 دقائق لـ EC2)، ثم تحتاج kubelet للتهيئة (~30–60 ثانية). المجموع: في الغالب 3–5 دقائق من حالة
Pendingإلى Pod يعمل. - محافظة مفرطة في التقليص: لن يُزيل CA عقدة إذا كان أي Pod غير مرتبط بـ controller عليها، أو إذا كان سيُخالف PodDisruptionBudget. هذا آمن لكنه يُبقي العقد الخاملة تعمل أطول من اللازم.
Karpenter — نموذج مختلف جوهرياً
يتخلى Karpenter (مشروع CNCF في مرحلة الحضانة، بُني أصلاً من AWS) عن مفهوم Node Group كلياً. بدلاً من إدارة ASGs، يستدعي Karpenter واجهات برمجة السحابة مباشرةً لتشغيل نوع instance تحديداً يناسب حمل العمل المُعلّق. هذا يُزيل طبقة ASG الوسيطة ويجعل التوفير أسرع وأكثر كفاءة من حيث التكلفة.
يُقدّم Karpenter مورديْن مُخصّصيْن (CRDs):
- NodePool — يحل محل
Provisionerالقديم (قبل الإصدار v0.32). يُعرّف عائلات instances المسموح بها، والمناطق، وأنواع الطاقة (on-demand أو spot)، والـ taints/labels، وميزانيات الإيقاع المتقطع. - EC2NodeClass (خاص بـ AWS) — يصف إعداد EC2 الأساسي: عائلة AMI، ومحددات الشبكة الفرعية، ومحددات مجموعة الأمان، وملف تعريف الـ instance، وبيانات المستخدم.
طاقة Spot: توفير 60–90% على الحوسبة
تُقدّم Spot Instances (AWS) / Preemptible VMs (GCP) / Spot VMs (Azure) خصومات كبيرة — أرخص عادةً بنسبة 60–90% من on-demand — مقابل إشعار إنهاء لمدة دقيقتين كحد أقصى. عند استخدامها صحيحاً، تُحدث spot فارقاً كبيراً لأحمال العمل الدُفعية والخدمات عديمة الحالة وحتى بعض الأحمال ذات الحالة مع معالجة مناسبة للإيقاع المتقطع.
قواعد الإنتاج لأحمال العمل الآمنة مع spot:
- حدّد دائماً
PodDisruptionBudget(PDB) حتى لا يستطيع Karpenter/CA إخلاء عدد كبير جداً من النسخ في وقت واحد. - وزّع الـ Pods عبر عائلات instances متعددة ومناطق توافر متعددة — مجمّعات spot هي لكل نوع instance لكل منطقة توافر؛ التنويع يُقلل بشكل كبير من خطر الإنهاء المتزامن.
- تعامل مع
SIGTERMبأناقة. يجب أن ينهي تطبيقك الطلبات الجارية ضمنterminationGracePeriodSeconds(يُوصى بـ 60–120 ثانية). - لا تُشغّل المكونات الحرجة الفردية (etcd، CA نفسه، admission webhooks) على spot أبداً.
يتعامل Karpenter مع إنهاء spot عبر قائمة انتظار SQS للإيقاع المتقطع: حين يُرسل EC2 إشعار إنهاء spot، يتلقاه Karpenter من SQS، يُغلق العقدة فوراً، ويبدأ جدولة طاقة بديلة — كل هذا قبل انتهاء نافذة الدقيقتين. هذا يُعطي MTTI أفضل بكثير مقارنةً بأسلوب node-problem-detector الافتراضي.
karpenter.k8s.aws/instance-category: [c, m, r] مجتمعاً مع instance-generation >= 4 عادةً 30–50 نوع instance مؤهل لكل منطقة — أوسع مجمّع spot ممكن، مما يُعظّم توافر الطاقة.
الدمج والتكثيف: القوة الخارقة لـ Karpenter
الدمج هو قدرة Karpenter على إعادة ضبط حجم أسطول العقد باستمرار. حين تكون العقد غير مُستغلة بالكامل، يُحاكي Karpenter ما إذا كانت جميع الـ Pods تستطيع الاستيعاب في عقد أقل (أو أصغر)، ثم يُنفّذ عملية تعبئة الصناديق: يُشغّل عقدة بديلة أرخص، يُخلّي العقد غير الكفؤة، ويترك الـ Pods لإعادة الجدولة. يحدث هذا بشكل مستقل، ضمن قيود PDB الخاصة بك، دون أي تدخل يدوي.
اضبط consolidationPolicy: WhenEmptyOrUnderutilized للدمج الكامل. استخدم WhenEmpty فقط للمستويات الإنتاجية الحساسة حيث تريد تجنب أي إيقاع متقطع طوعي للـ Pods العاملة.
consolidateAfter: 0s في الإنتاج. الدمج العدواني يُطلق دوراناً مستمراً للعقد، مما يُعطّل الـ Pods دون ضرورة وقد يُسبب إخفاقات متسلسلة إذا كانت أحمال عملك لها أوقات بدء بطيئة. قيمة من 1m إلى 5m تُعطي المجدول وقتاً للاستقرار بعد حدث توسعة قبل انطلاق جولة دمج أخرى.
مراقبة المُوسّع التلقائي أثناء العمل
اجمع Karpenter مع Kubernetes Metrics Server وHPA للحصول على مكدّس تحجيم تلقائي متكامل: يُوسّع HPA الـ Pods استجابةً لمقاييس CPU/الذاكرة/المخصصة، مما يُسبب Pods مُعلّقة حين تمتلئ العقد، ويُلاحظها Karpenter ويحلها بتشغيل طاقة جديدة. لا يتعارض المتحكمان أبداً — كل منهما يعمل على موارد مختلفة (Pods مقابل Nodes).