أحمال عمل Kubernetes وإعدادها

التوسع الأفقي التلقائي للـ Pods

18 دقيقة الدرس 8 من 32

التوسع الأفقي التلقائي للـ Pods

لا تبقى حركة المرور ثابتة أبدًا. تشهد خدمة الدفع عشرة أضعاف حِملها الاعتيادي خلال تخفيضات مفاجئة. تُضرب واجهة برمجة التطبيقات للتحليلات الدُّفعية بشدة كل صباح حين تُولَّد التقارير الليلية. تخصيص نُسَخ كافية لاستيعاب الذروة طوال الوقت يُبدِّد المال والمعالج في ساعات الهدوء. والتخصيص للمتوسط يُعرِّضك لفشل متسلسل في أسوأ لحظة ممكنة.

التوسع الأفقي التلقائي للـ Pods (HPA) هو حل Kubernetes لهذه المشكلة. بدلًا من تثبيت عدد النُّسَخ، تحدِّد حدًّا مستهدفًا للاستخدام — "احتفظ بمتوسط CPU عند 60%‏" — ويضبط تحكُّم HPA حقل replicas في Deployment باستمرار لتحقيق ذلك الهدف. النتيجة نظام منظِّم لذاته يتوسع أفقيًا تحت الحِمل ويتراجع عند انخفاض الحركة، تلقائيًا ودون تدخل مشغِّل. في Google وMeta وAWS، كل حِمل عمل عديم الحالة يعمل تحت مُوسِّع تلقائي. تحديد عدد النُّسَخ يدويًا يُعدّ نمطًا تشغيليًا مضادًا.

كيف تعمل حلقة التحكم في HPA

HPA متحكِّم Kubernetes يُشغِّل حلقة تسوية، عادةً كل 15 ثانية (قابلة للضبط عبر --horizontal-pod-autoscaler-sync-period في مدير التحكم). كل تكرار يتبع التسلسل ذاته:

  1. جمع المقاييس — الاستعلام عن Metrics Server (CPU/ذاكرة المدمجة) أو محوِّل مقاييس خارجي (مقاييس مخصصة/خارجية).
  2. حساب النُّسَخ المطلوبة — تطبيق صيغة التوسع: desiredReplicas = ceil(currentReplicas × currentMetricValue / desiredMetricValue).
  3. التحديد بالحدود — لا تنزل عن minReplicas ولا تتجاوز maxReplicas.
  4. تطبيق نافذة الاستقرار — مراعاة فترة التهدئة المُضبَّطة لمنع التذبذب.
  5. تحديث الهدف — كتابة عدد النُّسَخ الجديد في Deployment (أو StatefulSet وغيره).
HPA reconciliation loop Metrics Server CPU / Memory / Custom HPA Controller every 15 s reconcile loop Compute Desired Replicas ceil(current × actual / target) Clamp to Bounds min / max Replicas Stabilisation Window scale-down: 300 s default Deployment replicas field patched Pod Pod Pod scaled from 1 to 3 1. pull metrics 2. formula 3. clamp 4. stabilise 5. patch
حلقة تسوية HPA: تُستقصى المقاييس كل 15 ثانية، تُحسَب النُّسَخ المطلوبة وتُحدَّد بالحدود، تمنع نافذة الاستقرار التذبذب، ثم يُحدَّث Deployment.

المتطلبات المسبقة: Metrics Server

يعتمد HPA لقياسَي CPU والذاكرة على Metrics Server — إضافة كلاستر تسحب بيانات استخدام الموارد من kubelet وتعرضها عبر واجهة برمجة metrics.k8s.io المجمَّعة. معظم الكلاسترات المُدارة (EKS وGKE وAKS) تُثبِّته افتراضيًا. على كلاستر bare-metal أو kubeadm يجب تثبيته يدويًا.

# تثبيت Metrics Server (كلاسترات bare-metal / kubeadm) kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml # التحقق من تشغيله واستعداده kubectl get deployment metrics-server -n kube-system kubectl top nodes kubectl top pods -n production # إذا لم يكن Metrics Server جاهزًا، يظهر في HPA: "unable to get metrics" # لكلاسترات kind/minikube ذات الشهادات الذاتية التوقيع، أضف --kubelet-insecure-tls: kubectl patch deployment metrics-server -n kube-system \ --type='json' \ -p='[{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"--kubelet-insecure-tls"}]'

HPA الأساسي على CPU

أبسط HPA يستهدف متوسط استخدام CPU عبر كل الـ Pods في Deployment. نسبة الاستخدام نسبية إلى طلب CPU للحاوية، لا إلى إجمالي CPU في العقدة — لذا يجب أن تُعلن كل حاوية في Deployment عن طلب CPU لكي يعمل HPA بصحة.

# --- ملف HPA التصريحي (مفضَّل — احفظه في Git) --- # hpa-api.yaml apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: api-hpa namespace: production spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: my-api minReplicas: 2 maxReplicas: 20 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 60 # استهداف 60% من طلب CPU لكل Pod --- # يجب أن يحمل Deployment طلبات CPU وإلا لا يستطيع HPA حساب الاستخدام # مقتطف من مواصفات Deployment: # resources: # requests: # cpu: "500m" # memory: "256Mi" # limits: # cpu: "2" # memory: "1Gi" # تطبيق والتحقق kubectl apply -f hpa-api.yaml kubectl get hpa api-hpa -n production kubectl describe hpa api-hpa -n production # الصيغة الأمرية السريعة (مفيدة للاختبار فقط، غير مناسبة للإنتاج) kubectl autoscale deployment my-api \ --cpu-percent=60 \ --min=2 \ --max=20 \ -n production
HPA والطلبات مرتبطان لا ينفصلان: يحسب HPA الاستخدام بـ CPU الفعلي / طلب CPU. إذا لم تُعلن حاوية عن طلب CPU، لا يستطيع Metrics Server حساب النسبة، ويُظهر سجل أحداث HPA missing request for cpu. احرص دائمًا على ضبط requests وlimits لكل حاوية في Deployment يُديرها HPA — تُطبِّق Google هذا عبر webhooks قبول LimitRange ترفض الـ Pods التي تفتقر إلى الطلبات.

التوسع على الذاكرة

يختلف توسع الذاكرة عن توسع CPU في جانب حاسم واحد: الذاكرة غير قابلة للضغط. حين يستخدم Pod نسبة 90% من طلب ذاكرته، لا يمكنك تقليله — يجب التوسع أفقيًا. غير أن HPA المبني على الذاكرة يجب ضبطه بعناية لأن الذاكرة كثيرًا ما لا تنخفض بعد حدث التوسع (الـ Pods القديمة لا تزال تحتفظ بتخصيصات الكومة)، مما قد يُطلق حلقات توسع إضافية. في شركات التقنية الكبرى النمط المفضَّل هو التوسع على CPU أو معدل الطلبات (مقياس مخصص)، واستخدام طلبات الذاكرة أساسًا كتلميح للجدولة مدعومًا بتوصيات Vertical Pod Autoscaler.

# HPA يستهدف CPU والذاكرة معًا (يأخذ HPA v2 العدد الأعلى من النُّسَخ المطلوبة) apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: api-hpa namespace: production spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: my-api minReplicas: 2 maxReplicas: 20 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 60 - type: Resource resource: name: memory target: type: AverageValue averageValue: 512Mi # قيمة مطلقة وليس نسبة مئوية

المقاييس المخصصة والخارجية

CPU والذاكرة مؤشرات متأخرة — ترتفع بعد أن يكون مستخدموك قد تأثروا بالتأخير أصلًا. تنمو الأنظمة الإنتاجية على نطاق واسع بناءً على مؤشرات سابقة: الطلبات في الثانية (RPS)، وعمق قائمة الانتظار، وزمن الاستجابة p99، أو حتى توقعات الحِمل المجدوَلة. يتطلب ذلك واجهة برمجة المقاييس المخصصة (custom.metrics.k8s.io) أو واجهة برمجة المقاييس الخارجية (external.metrics.k8s.io). تشمل المحولات الشائعة KEDA (التوسع التلقائي المدفوع بالأحداث في Kubernetes)، وPrometheus Adapter، ومحولات السحابة الأصيلة (Datadog وStackdriver).

# HPA على مقياس مخصص: "http_requests_per_second" من Prometheus (عبر Prometheus Adapter) apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: api-hpa namespace: production spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: my-api minReplicas: 2 maxReplicas: 50 metrics: - type: Pods pods: metric: name: http_requests_per_second # مسجَّل في إعداد Prometheus Adapter target: type: AverageValue averageValue: "500" # 500 طلب في الثانية لكل Pod - type: External external: metric: name: sqs_queue_depth # مقياس AWS SQS عبر محوِّل خارجي selector: matchLabels: queue: orders target: type: AverageValue averageValue: "100" # توسع للحفاظ على <100 رسالة لكل Pod
KEDA للتوسع المدفوع بالأحداث: KEDA (keda.sh) هو الطريقة القياسية في الصناعة للتوسع التلقائي على مصادر الأحداث الخارجية — SQS وKafka وRabbitMQ وAzure Service Bus وPub/Sub وأكثر من 60 مصدرًا آخر. يُثبَّت كـ CRD يُنشئ ويُدير HPAs تحت الغطاء. يدعم أيضًا التوسع إلى الصفر، وهو ما لا يستطيع HPA الأصيل فعله (الحد الأدنى نسخة واحدة). إذا كان حِمل عملك مستهلكًا لقائمة انتظار، يتوسع KEDA بناءً على عمق القائمة ويصمد على الصفر حين تكون فارغة — وفرًا كبيرًا في التكلفة.

ضبط السلوك: منع التذبذب

سلوك HPA الافتراضي يعمل لمعظم الحالات لكنه عدواني للغاية مع الخدمات الحساسة للكمون. ارتفاع مفاجئ قد يُسبِّب توسعًا، وبعد ثوانٍ تعود المقاييس إلى الأسفل مسببةً تراجعًا — حلقة تذبذب تُنشئ كمون بدء Pods مع كل تذبحٍ. كتلة behavior (autoscaling/v2) تمنحك تحكمًا دقيقًا.

# HPA للإنتاج: توسع سريع وتراجع محافظ apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: api-hpa namespace: production spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: my-api minReplicas: 3 maxReplicas: 100 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 60 behavior: scaleUp: stabilizationWindowSeconds: 0 # توسع فوري (بدون تهدئة) policies: - type: Percent value: 100 # مضاعفة النُّسَخ كحد أقصى لكل فترة periodSeconds: 15 - type: Pods value: 4 # أو إضافة 4 Pods كحد أقصى لكل فترة periodSeconds: 15 selectPolicy: Max # اختر السياسة التي تضيف أكبر عدد من الـ Pods scaleDown: stabilizationWindowSeconds: 300 # انتظر 5 دقائق من الاستقرار قبل التراجع policies: - type: Percent value: 10 # احذف 10% من النُّسَخ كحد أقصى لكل فترة periodSeconds: 60 selectPolicy: Min # اختر السياسة التي تحذف أقل عدد من الـ Pods
نافذة التراجع الافتراضية 5 دقائق — لا تقلِّصها باستهتار. تمنع نافذة الاستقرار التذبذب بإلزام HPA برؤية قراءة حِمل منخفض مستقرة طوال النافذة بأكملها قبل التراجع. تقليلها إلى 0 يعني أن أي هدوء مروري مؤقت يُطلق تراجعًا، مما ينشئ Pods جديدة عند الارتفاع التالي — وبدء كل Pod يضيف كمونًا (سحب الصورة، إحماء JVM وغيرها). توصية Google SRE هي الاحتفاظ بنافذة التراجع بين 5-10 دقائق لخدمات الويب وعدم النزول إلى ما دون دقيقتين.

مراقبة HPA وتصحيحه

حين لا يتصرف HPA كما هو متوقع، kubectl describe hpa هو أداتك الأولى. قسم Events وجدول Conditions يُخبرانك بالضبط بما رآه المتحكِّم ولماذا اتخذ (أو لم يتخذ) قرار التوسع.

# حالة HPA في الوقت الفعلي — تعرض الحالي / المطلوب / الأدنى / الأقصى وقيم المقاييس kubectl get hpa -n production -w # تفاصيل كاملة: الشروط، والأحداث، وآخر قرار توسع kubectl describe hpa api-hpa -n production # محاكاة حِمل لاختبار التوسع (شغِّل في طرفية منفصلة) kubectl run -i --tty load-gen \ --image=busybox:1.36 \ --rm \ --restart=Never \ -n production \ -- /bin/sh -c "while true; do wget -q -O- http://my-api-svc/; done" # التحقق من إرجاع Metrics Server لمقاييس مستوى Pod kubectl top pods -n production --sort-by=cpu # فحص أحداث HPA للأخطاء (مقاييس مفقودة، كائن غير موجود وغيرها) kubectl get events -n production --field-selector reason=SuccessfulRescale kubectl get events -n production --field-selector reason=FailedGetScale # فحص حالة المُوسِّع التلقائي بالتفصيل kubectl get hpa api-hpa -n production -o yaml | grep -A 20 status:
HPA لا يُغني عن Cluster Autoscaler. يُضيف HPA Pods إلى العقد الموجودة. إذا كانت جميع العقد ممتلئة، ستبقى الـ Pods الجديدة في حالة Pending حتى تتوفر عقدة. على كلاسترات السحابة، يراقب Cluster Autoscaler (أو Karpenter على EKS) الـ Pods المعلَّقة ويُهيِّئ عقدًا جديدة. المُوسِّعان مصمَّمان للعمل معًا: HPA يتولى التوسع على مستوى Pod، وCluster Autoscaler يتولى التوسع على مستوى العقدة. يجب ضبط كليهما بتناسق لتحقيق كلاستر يُصحِّح نفسه بالكامل ويُحقِّق التوازن الأمثل في التكلفة.