التوسع التلقائي للعنقود وKarpenter
التوسع التلقائي للعنقود وKarpenter
يعمل كلٌّ من HPA وVPA داخل نطاق مجموعة العُقد الموجودة فحسب — يعيدان توزيع الحاويات ويضبطان طلبات الموارد، لكنهما لا يستطيعان إنشاء طاقة جديدة حين ينفد الـCPU أو الذاكرة المخصَّصة في العنقود. تقع تلك المسؤولية على طبقة التوسع التلقائي للعنقود. تتناول هذه الدرس المقاربتين الرئيسيتين على Kubernetes: Cluster Autoscaler (CA) العريق، وبديله الحديث من AWS المسمى Karpenter. نغطي أيضاً تكامل مثيلات Spot وتوحيد العُقد وأنماط الفشل الإنتاجية التي تفاجئ المهندسين في بيئات الإنتاج الكبيرة.
كيف يعمل Cluster Autoscaler
يراقب CA الحاويات ذات الحالة Unschedulable — أي الحاويات التي وضعها المجدول في حالة انتظار لعدم توفر طاقة كافية على أيٍّ من العُقد. حين يرصد CA مثل هذه الحاوية، يحاكي ما إذا كانت إضافة عقدة من مجموعة ASG المُكوَّنة ستُتيح جدولتها. إذا كانت الإجابة نعم، يطلق CA عملية توسع في ASG. على مسار التقليص، يفحص CA دورياً ما إذا كان يمكن إعادة توزيع حاويات أي عقدة على بقية العنقود؛ إذا أمكن ذلك، يُقيِّد العقدة ويُصرِّف حاوياتها مع احترام PodDisruptionBudgets، ثم يطلق تقليص ASG.
معاملات الضبط المهمة على نطاق الإنتاج:
--scale-down-utilization-threshold(الافتراضي 0.5) — تُعدّ العقدة ضعيفة الاستخدام إذا كان طلب الـCPU والذاكرة معاً أقل من هذه النسبة. رفعها إلى 0.7 على العناقيد الحساسة للتكلفة يُسرِّع التوحيد لكنه يُخاطر بالاضطراب عند الأحمال المتذبذبة.--scale-down-delay-after-add(الافتراضي 10m) — المدة بعد حدث التوسع قبل إعادة تقييم التقليص. إن كانت قصيرة جداً، ستحدث تذبذبات متكررة؛ 15–20 دقيقة أكثر أماناً للأحمال ذات الأشكال غير المنتظمة.--max-node-provision-time(الافتراضي 15m) — يتخلى CA عن مجموعة العُقد إذا لم تصبح العقدة جاهزة خلال هذه المهلة. مع مثيلات Spot، اضبطها على 8–10m للإخفاق السريع والتحول لمجموعة أخرى.--balance-similar-node-groups— ضروري لنشر متعدد مناطق التوفر: يجبر CA على التوسع بالتساوي بين المناطق بدلاً من ملء منطقة واحدة أولاً.
Karpenter: المقاربة الحديثة
يتبنى Karpenter (مشروع CNCF، أصيل لـAWS) معمارية مختلفة جذرياً. بدلاً من إدارة مجموعات ASG، يستدعي Karpenter مباشرةً EC2 RunInstances API لتوفير مثيلات فردية. بدلاً من مجموعات عُقد بأحجام ثابتة، تُعرِّف NodePools تصف القيود — عائلات المثيلات والمعماريات وأنواع الطاقة — ويختار Karpenter المثيل الأمثل في الوقت الفعلي عبر تحزيم الحاويات المعلَّقة مقابل أسعار EC2 الحية وتوافرها.
تنخفض زمن الإمداد من 3–5 دقائق المعتادة لـCA (إطلاق ASG + تمهيد AMI + تسجيل kubelet) إلى أقل من 60 ثانية لمعظم أنواع المثيلات. والأهم أن Karpenter يختار الحجم المناسب تماماً لدفعة الحاويات المعلَّقة دون الاضطرار للتقريب صعوداً إلى الحجم التالي في ASG.
تدفق توفير العُقد
يوضح المخطط أدناه مسار التوفير عبر CA (من خلال ASG) مقارنةً بمسار Karpenter المباشر إلى EC2. فهم هذا يُساعدك على الاستدلال حول ميزانيات زمن الاستجابة وأنماط الفشل عند ارتفاعات الحركة.
استراتيجية مثيلات Spot
تشغيل غالبية الأحمال عديمة الحالة والمتسامحة مع الانقطاع على مثيلات Spot يُخفِّض تكاليف EC2 بنسبة 60–80%. المقاربة الصحيحة هي التنويع: توزيع الطلبات على عائلات وأحجام متعددة حتى لا يُفرِغ انقطاع مجموعة Spot واحدة طاقتك. يتعامل Karpenter مع هذا أصلياً عبر تقييم أنواع مثيلات متعددة في كل NodePool. مع CA تحقق التنويع بتعريف ASGs متعددة وضبط --expander=least-waste.
التعامل الرشيق مع انقطاعات Spot يتطلب أمرين:
- معالجة إشعار الانقطاع — يُرسل EC2 تحذيراً قبل دقيقتين من استرداد المثيل. يتكامل Karpenter مع طابور SQS لاستقبال هذه الأحداث وتقييد العقدة وتصريفها قبل انتهاء النافذة. بدون هذا ستتلقى حاوياتك SIGKILL دون تصريف.
- حدود انقطاع الحاوية (PDB) — كل نشر إنتاجي يحتاج PDB حتى لا تُلغي عملية التصريف أكثر من نسبة آمنة من النسخ في وقت واحد. التكوين الشائع هو
minAvailable: 50%للخدمات عديمة الحالة.
توحيد العُقد (Consolidation)
التوفير نصف القصة فقط. العنقود الذي يتوسع عند ارتفاع الحركة سيتراكم فيه عُقد ضعيفة الاستخدام بعد تراجع الحركة. التوحيد هو عملية ضغط الأحمال على عُقد أقل وإنهاء الفائض.
يعمل محرك توحيد Karpenter (consolidationPolicy: WhenEmptyOrUnderutilized) بشكل مستمر. يقيِّم كل عقدة لمعرفة أين يمكن إعادة جدولة حاوياتها. حين يجد حركة توحيد صالحة — إفراغ عقدة كلياً أو استبدالها بمثيل أصغر/أرخص — ينفذ Karpenter دورة التصريف ثم التوفير. هذا أكثر عدوانية بكثير من تقليص CA الذي لا يُخلي إلا العُقد التي أصبحت فارغة تلقائياً.
WhenEmptyOrUnderutilized مع consolidateAfter: 30s للعناقيد ذات الخدمات الصغيرة عديمة الحالة — يحافظ على التكاليف ضيقة. للأحمال ذات الحالة (قواعد البيانات، وسطاء Kafka) استخدم WhenEmpty فقط، أو أضف تعليق karpenter.sh/do-not-disrupt: "true" لاستثناء تلك الحاويات من التوحيد.
أنماط الفشل الإنتاجية
عدة أنماط فشل تظهر بانتظام في نشر Karpenter على نطاق واسع:
- بلوغ حدود NodePool: حين يُستنفد
limits.cpuأوlimits.memory، يتوقف Karpenter عن التوفير وتبقى الحاويات معلَّقة إلى أجل غير مسمى. راقبkarpenter_nodepools_limit_usage_percentageوأطلق تنبيهاً قبل 90%. - فشل التمهيد بسبب انجراف AMI: إذا أصدر
al2023@latestإصداراً معيباً، فكل عقدة جديدة تفشل في الانضمام للعنقود. ثبِّت نسخة محددة أثناء الأعطال:al2023@v20250501. تابعkarpenter_nodes_total{phase="NotReady"}في منظومة التنبيه. - تذبذب التوحيد: إذا كان HPA متسرعاً في التقليص والتوحيد عدوانياً، قد تدخل في حلقة: HPA يُقلِّص -> Karpenter يوحِّد -> ارتفاع مفاجئ -> HPA يتوسع -> Karpenter يوفِّر. خفِّف هذا بضبط نوافذ تثبيت التقليص في KEDA أو HPA أطول من نافذة التوحيد.
- PDB يعيق التصريف: إذا كان
minAvailableفي PDB مساوياً للعدد الكلي من النسخ (خطأ شائع)، يُحجب الإخلاء بشكل دائم ويتوقف التوحيد. افحص PDBs بانتظام بـkubectl get pdb -A.