تخطيط السعة والتوسع التلقائي

VPA وضبط حجم الموارد

18 دقيقة الدرس 4 من 27

VPA وضبط حجم الموارد

يعمل HPA الأفقي عبر إضافة نسخ جديدة من الـ Pod. أما Vertical Pod Autoscaler (VPA) فيتبع نهجاً مختلفاً: يراقب الحِمل الفعلي للتطبيق عبر الزمن ثم يوصي — أو يُطبّق مباشرةً — بقيم أفضل لـ requests وlimits الخاصة بالـ CPU والذاكرة. على نطاق إنتاجي واسع، لا يُعدّ VPA اختيارياً. الـ Pods ذات الـ requests المُبالَغ فيها تُجوّع المُجدوِل من السعة القابلة للتخصيص؛ والـ Pods ذات الـ requests غير الكافية تصطدم بـ OOMKill أو تُكبَّل بالـ CPU throttling بما يعجز مع مؤشرات الأداء الزمني. إن ضبط الحجم الصحيح هو الطريقة التي تُستعاد بها 30-50% من تكلفة الـ Cluster دون تعديل سطر واحد من كود التطبيق.

آلية عمل VPA من الداخل

يتكوّن VPA من ثلاثة Controllers تعمل في نطاق kube-system (أو نطاق مخصص عند النشر عبر المانيفستات الرسمية):

  • Recommender: يراقب باستمرار بيانات استخدام CPU والذاكرة عبر Metrics API ويبني توصية باستخدام المتوسط المتحرك المُرجَّح أسياً (EWMA). يأخذ في الحسبان ذروة الاستخدام أيضاً — فالتوصية تعلو عن الوسيط عمداً لاستيعاب الارتفاعات المفاجئة.
  • Admission Controller (webhook): يعترض إنشاء الـ Pod ويُعدّل قيم الموارد عند الإنشاء. هذا هو مسار العمل في وضعَي Auto وInitial.
  • Updater: في وضع Auto، يُخلي (يُزيل) الـ Pods التي تنحرف قيم مواردها انحرافاً كبيراً عن التوصية، مما يتيح لـ Admission Controller إعادة كتابتها عند إعادة التشغيل. يحترم عملية الإخلاء قواعد PodDisruptionBudget.
VPA وHPA لا يتشاركان المقياس ذاته. إذا كان HPA يتوسع بناءً على استخدام CPU (الأكثر شيوعاً)، فإن تفعيل VPA في وضع Auto يُوجد حلقة تغذية راجعة: يرفع VPA قيمة CPU request، فينخفض نسبة الاستخدام المُلاحظة، فيُقلّص HPA عدد الـ Pods، فيتركّز الحِمل، فيرفع VPA التوصية من جديد. الحل الآمن هو تشغيل HPA على مقاييس مخصصة (معدل الطلبات، عمق الطابور) بينما يتولى VPA إدارة الـ requests والـ limits.

تثبيت VPA

VPA ليس مُضمَّناً في Kubernetes ويجب تثبيته من مستودع autoscaler. يستهدف التثبيت الافتراضي نطاق kube-system ويستخدم شهادة موقّعة ذاتياً لـ Admission Webhook.

# استنساخ مستودع autoscaler الرسمي (ثبّت على إصدار محدد في الإنتاج) git clone https://github.com/kubernetes/autoscaler.git cd autoscaler/vertical-pod-autoscaler # توليد الشهادات ونشر المكوّنات الثلاثة ./hack/vpa-up.sh # التحقق من تشغيل المكوّنات الثلاثة kubectl -n kube-system get pods | grep vpa # vpa-admission-controller-xxxx 1/1 Running # vpa-recommender-xxxx 1/1 Running # vpa-updater-xxxx 1/1 Running

أوضاع تحديث VPA

يتحكم حقل updatePolicy.updateMode في مدى تطبيق VPA لتوصياته بشكل مباشر. اختر الوضع المناسب بناءً على مدى تقبّل حِمل العمل لديك لإعادة تشغيل الـ Pod:

  • Off — يعمل Recommender ويكتب التوصيات في حالة VPA دون تطبيق أي شيء تلقائياً. استخدم هذا الوضع لأول 7-14 يوماً مع أي حِمل عمل جديد لمراجعة التوصيات قبل الوثوق بها.
  • Initial — يُطبّق Admission Controller التوصيات عند إنشاء الـ Pod فقط. لا يُخلَى أي Pod موجود. آمن للأحمال ذات الحالة (Stateful) أو حين تكون إعادة التشغيل مكلفة.
  • Recreate — يُخلي Updater الـ Pods حين تنحرف قيم مواردها انحرافاً كبيراً عن التوصية، لكن فقط إذا سمح بذلك PDB. مفيد للـ Deployments ذات النسخ المتعددة.
  • Auto — مماثل لـ Recreate حالياً؛ قد يستخدم تحديثاً في المكان (in-place resize) عند استقرار Kubernetes KEP-1287 (ألفا في الإصدار 1.27+).
# كائن VPA يستهدف Deployment لخادم API — ابدأ بوضع Off لجمع البيانات apiVersion: autoscaling.k8s.io/v1 kind: VerticalPodAutoscaler metadata: name: api-server-vpa namespace: production spec: targetRef: apiVersion: apps/v1 kind: Deployment name: api-server updatePolicy: updateMode: "Off" resourcePolicy: containerPolicies: - containerName: api minAllowed: cpu: 100m memory: 128Mi maxAllowed: cpu: 4000m memory: 8Gi controlledResources: - cpu - memory controlledValues: RequestsAndLimits

بعد أسبوع، افحص التوصية:

kubectl describe vpa api-server-vpa -n production # ابحث عن قسم Recommendation: # Recommendation: # Container Recommendations: # Container Name: api # Lower Bound: # Cpu: 250m # Memory: 512Mi # Target: # Cpu: 620m # Memory: 920Mi # Uncapped Target: # Cpu: 620m # Memory: 920Mi # Upper Bound: # Cpu: 2100m # Memory: 3Gi # # Target هو ما سيُحدده VPA كـ request جديد. # Upper Bound يأخذ في الحسبان ذروة الحركة المُلاحظة في فترة الرصد.

Goldilocks: تحليل ضبط الحجم على مستوى الأسطول

تشغيل كائنات VPA منفردة لكل حِمل عمل في وضع Off هو النهج الصحيح، لكن قراءة kubectl describe vpa لـ 200 Deployment ليس عملياً. تُؤتمت أداة Goldilocks (من Fairwinds) هذا العمل: تُنشئ كائن VPA في وضع Off لكل Deployment في النطاق الذي تُعلّمه، ثم تعرض لوحة تحكم ويب تقارن الـ requests الحالية بالموصى بها جنباً إلى جنب مع تقدير وفر التكلفة الشهري.

# تثبيت Goldilocks عبر Helm helm repo add fairwinds-stable https://charts.fairwinds.com/stable helm install goldilocks fairwinds-stable/goldilocks \ --namespace goldilocks \ --create-namespace # تعليم النطاق الذي تريد مراقبته kubectl label namespace production goldilocks.fairwinds.com/enabled=true # إعادة توجيه لوحة التحكم محلياً kubectl -n goldilocks port-forward svc/goldilocks-dashboard 8080:80 # افتح http://localhost:8080 — تعرض جميع Deployments في النطاقات المُعلَّمة # مع أعمدة: الطلب الحالي، هدف VPA، الوفر الشهري المقدَّر
VPA component flow and Goldilocks analysis loop Metrics Server CPU / Mem usage VPA Recommender EWMA + peak model VPA Object status.recommendation Admission Webhook mutates pod on create VPA Updater evicts drifted pods Goldilocks dashboard + savings metrics writes rec reads rec reads rec reads VPAs
تدفق مكوّنات VPA الثلاثة: يقرأ Recommender المقاييس، ويكتب التوصيات، ويُطبّقها Webhook والـ Updater. يقرأ Goldilocks كائنات VPA على مستوى الأسطول لتحليل التكاليف.

ضبط حدود resourcePolicy بشكل صحيح

بدون حدود، سيوصي VPA بأي شيء يراه نموذجه — ربما يُوصي بتخصيص 32 GiB ذاكرة لحِمل عمل مرّ به حدث OOM استثنائي واحد، أو يُخفّض طلب CPU إلى 10m لوظيفة batch تكون خاملة في الليل. دائماً حدّد minAllowed وmaxAllowed لكل container:

  • minAllowed — لا تسمح لـ VPA بالنزول دون الحد الأدنى المعروف للتشغيل، أو إحماء JVM Heap، أو نسبة نجاح فحوصات الصحة. لخدمات Java، الحد الآمن عادةً 512Mi ذاكرة حتى للنسخ ذات الحِمل الخفيف.
  • maxAllowed — قيّد التوصية بنسبة من سعة أكبر Node متاحة. توصية تتجاوز 50% من الـ allocatable resource للـ Node تُقلّل كثافة الـ Pods وتُهزم الهدف منها.
  • controlledValues: RequestsOnly مقابل RequestsAndLimits — للـ CPU، فضّل RequestsOnly دون CPU limit (نمط موصى به من Google لتجنب CFS throttling). للذاكرة، استخدم RequestsAndLimits لتتناسب حدود OOM مع الاستخدام الفعلي.
نمط "لا CPU limit": توصي إرشادات إنتاج Google الداخلية (ووثائق Kubernetes) بحذف CPU limits كلياً من الخدمات الحساسة للاستجابة الزمنية. CFS throttling صامت لا يولّد أحداثاً ويُسبّب ارتفاعات في زمن الاستجابة p99 تبدو كتراجعات في التطبيق. حدّد requests.cpu فقط ليتمكن المُجدوِل من التوزيع الصحيح، ودع Scheduler العادل للـ Node يتعامل مع الارتفاعات. استخدم controlledValues: RequestsOnly في VPA لمنعه من ضبط CPU limit.

أنماط الفشل الإنتاجي التي يجب معرفتها

أفضى VPA في وضع Auto إلى إخلاء Deployments بأكملها في السيناريوهات التالية — جميعها موثّقة في بيئات إنتاجية حقيقية:

  • سوء ضبط PDB: Deployment بثلاث نسخ وmaxUnavailable: 3 (أو بدون PDB) يسمح لـ VPA Updater بإخلاء جميع الـ Pods دفعةً واحدة. طبّق PDB بحد أدنى minAvailable: 1 أو maxUnavailable: 33% لكل Deployment يخدم حركة مرور.
  • تضخيم Cold Start: حِمل عمل يستهلك CPU قليلاً في وقت الخمول لكنه يرتفع حاداً عند أول طلب (Node.js، Python مع imports كسولة، JVM). يُلاحظ VPA الاستهلاك الخامل ويخفض طلب CPU. عند أول نشر، تُعاد تشغيل الـ Pods بطلب CPU منخفض، فيُسبّب إحماء JVM تكبيلاً، تفشل فحوصات الصحة، تُعيد الـ Deployment نشرها القديم، وتتكرر الدورة. الحل: ضبط minAllowed.cpu على استهلاك p95 الإحماء المقاس.
  • تذبذب التوصيات: حِمل عمل ذو ذاكرة متغيرة بشدة (مثل وظيفة batch ممزوجة مع خادم ويب في الـ Pod ذاتها). يتأرجح VPA بين توصيات منخفضة وعالية مما يُسبّب إخلاءات متكررة. الحل: افصل batch عن web في containers أو Deployments مستقلة لكي يُنمذج VPA كلاً منهما باستقلالية.
لا تشغّل VPA في وضع Auto على Deployments أحادية النسخة أو StatefulSets في الإنتاج دون إجراء إعادة تشغيل موثّقة. يحترم VPA Updater قواعد PDB، لكن إذا كان minAvailable: 1 ولديك نسخة واحدة فقط، تُحجب عملية الإخلاء — وبذلك لا تُطبَّق التوصية أبداً. النهج الصحيح للأحمال أحادية النسخة هو وضع Initial وإعادة التشغيل اليدوية خلال نافذة صيانة مجدوَلة.

دمج توصيات VPA في سير عمل GitOps

في سير عمل GitOps (ArgoCD أو Flux)، يتعارض وضع Auto في VPA مع المُتوافق (Reconciler): يُعدّل VPA مواصفات الـ Pod داخل الـ Cluster فيما يُعيد المُتوافق Deployment Manifest في git إلى قيم الـ requests الأصلية. الحل الموثّق هو إبقاء VPA في وضع Off، وتصدير التوصيات دورياً، وإعادة تغذيتها في git عبر مرحلة في مسار CI.

#!/bin/bash # تصدير توصيات VPA لجميع كائناته في نطاق معيّن # يُشغَّل كوظيفة CI مجدوَلة ويفتح Pull Request بالتغييرات NAMESPACE=production OUTPUT_DIR=k8s/resource-recommendations mkdir -p "$OUTPUT_DIR" for vpa in $(kubectl get vpa -n "$NAMESPACE" -o jsonpath='{.items[*].metadata.name}'); do TARGET=$(kubectl get vpa "$vpa" -n "$NAMESPACE" \ -o jsonpath='{.spec.targetRef.name}') CPU_REC=$(kubectl get vpa "$vpa" -n "$NAMESPACE" \ -o jsonpath='{.status.recommendation.containerRecommendations[0].target.cpu}') MEM_REC=$(kubectl get vpa "$vpa" -n "$NAMESPACE" \ -o jsonpath='{.status.recommendation.containerRecommendations[0].target.memory}') echo "Deployment: $TARGET | CPU: $CPU_REC | Memory: $MEM_REC" \ >> "$OUTPUT_DIR/recommendations.txt" done # افحص الفروق عن القيم الملتزمة ثم افتح Pull Request git diff --exit-code "$OUTPUT_DIR/" || \ gh pr create --title "chore: VPA resource recommendations $(date +%F)" \ --body "Automated VPA recommendation export. Review before merging." \ --base main

هذا النهج يُبقي git مرجعاً للحقيقة الوحيدة مع الاستفادة من تحليل VPA القائم على البيانات. تعتمد فرق هندسة على مستوى Spotify وShopify وشركات مماثلة الحجم هذا النمط لإجراء مراجعات ضبط الحجم ربع السنوية بدلاً من الاعتماد على التعديل التلقائي الكامل في الإنتاج.