pod عالق في Pending أو يظهر أحداث FailedScheduling يعني جدولة Kubernetes لا يمكنها العثور على عقدة مناسبة لتشغيله. يوضح هذا الدليل كيفية التشخيص وإصلاح الأسباب الأكثر شيوعاً.
الأعراض
حالة pod هي Pending ولا تتقدم إلى Running. تشغيل kubectl describe pod يظهر أحداث مثل:
Name: example-app-5f7c9d4bfb-7x8kq
Namespace: default
Status: Pending
Events:
Type Reason Age Message
---- ------ ---- -------
Warning FailedScheduling 3m 0/3 nodes are available:
insufficient cpu on 3 nodes
رسائل أخرى ممكنة:
insufficient memory on 3 nodes
node has a taint...that the pod does not tolerate
pod has unbound immediate PersistentVolumeClaims
no nodes match the pod's node selector
pod affinity/anti-affinity not satisfied
exceeds quota
exceeds LimitRange
لماذا يحدث
مرتبة حسب الاحتمالية:
- CPU أو ذاكرة ناقصة على جميع العقد — يطلب pod موارد أكثر من أي عقدة متاحة. إما أن العنقود مفرط الاشتراك أو طلبات pod غير واقعية.
- node selector أو affinity constraint غير مرضي — pod مقيد لعقد معينة (حسب التسمية أو قواعد affinity) وتلك العقد غير موجودة أو غير متاحة.
- Taints على العقد التي pod لا يتسامح معها — عقد المستوى التحكم والعقد المتخصصة الأخرى لها taints. Pods بدون tolerations مطابقة لا يمكنها الجدولة هناك.
- PersistentVolumeClaim (PVC) pending — PVC لا يمكنه الارتباط بـ PersistentVolume، لذا pod ينتظر بلا نهاية.
- Pod quota أو LimitRange تجاوزت — Namespace لديه resource quotas أو limit ranges تمنع إنشاء pods جديدة.
- Topology spread constraints أو pod anti-affinity — يتطلب pod نشر عبر عقد أو لا يمكنه العمل على نفس العقدة مثل pods أخرى، لكن لا عقد مناسبة موجودة.
الحل
1. CPU أو ذاكرة ناقصة على جميع العقد
تحقق من الموارد المتاحة:
kubectl top nodes
مثال إخراج:
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
node-1 1900m 95% 3800Mi 95%
node-2 1800m 90% 3600Mi 90%
node-3 1950m 98% 3900Mi 98%
جميع العقد ممتلئة. اعرض ما يستهلك الموارد:
kubectl top pod -A | sort --reverse --numeric-sort --key 3 | head -20
الخيار أ: قيّم أو احذف pods ذات أولوية منخفضة لتحرير مساحة.
الخيار ب: زد طلبات الموارد للـ pod إذا كانت عالية جداً:
kubectl get pod <pod-name> -o yaml | grep -A 5 "resources:"
إذا كان pod يطلب 1000m CPU لكن العقد لديها فقط 100m حر، قلل الطلبات:
resources:
requests:
cpu: "100m" # قلل من 500m
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
طبّق وأعد المحاولة:
kubectl apply -f deployment.yaml
الخيار ج: أضف مزيد من العقد للعنقود.
لعناقيد السحابة، فعّل autoscaling:
# مثال GKE
gcloud container clusters update <cluster-name> \
--enable-autoscaling \
--min-nodes 1 \
--max-nodes 10
للمعادن أو on-prem، أضف العقد يدوياً:
# اتبع تعليمات مزود السحابة أو أداة النشر
2. Node selector أو affinity constraint غير مرضي
تحقق من node selector للـ pod:
kubectl get pod <pod-name> -o yaml | grep -A 5 "nodeSelector:"
مثال:
nodeSelector:
disktype: ssd
gpu: "true"
سيعمل pod فقط على عقد بكلا التسميتين. تحقق إذا كانت أي عقد لديها هذه التسميات:
kubectl get nodes --show-labels | grep ssd
kubectl get nodes --show-labels | grep gpu
إذا لم توجد عقد مطابقة، إما:
أ. أضف التسميات لعقد موجودة:
kubectl label node <node-name> disktype=ssd gpu=true
ب. أزل nodeSelector من pod إذا لم يكن مطلوباً بالفعل:
# أزل أو أعلّق nodeSelector
# nodeSelector:
# disktype: ssd
لـ affinity constraints (أكثر تعقيداً من nodeSelector)، تحقق من مواصفات pod:
kubectl get pod <pod-name> -o yaml | grep -A 20 "affinity:"
مثال affinity يتطلب تسمية معينة:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd
إذا لم توجد عقد بالتسمية المطلوبة، أضفها أو أرخِ affinity لتفضيل:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution: # تغيير من required
- preference:
matchExpressions:
- key: disktype
operator: In
values:
- ssd
weight: 100
طبّق pod المحدّث:
kubectl apply -f deployment.yaml
kubectl rollout restart deployment/<deployment-name>
3. Taints على العقد التي pod لا يتسامح معها
عقد المستوى التحكم والعقد المتخصصة الأخرى لها taints. تحقق منها:
kubectl describe node <node-name> | grep Taint
مثال إخراج:
Taints: node-role.kubernetes.io/control-plane:NoSchedule
هذا taint يعني pods لا يمكنهم العمل على المستوى التحكم إلا إذا تسامحوا معه. إذا كان pod يجب أن يُسمح له هناك، أضف toleration مطابق:
apiVersion: apps/v1
kind: Deployment
metadata:
name: special-app
spec:
template:
spec:
tolerations:
- key: "node-role.kubernetes.io/control-plane"
operator: "Equal"
value: ""
effect: "NoSchedule"
containers:
- name: app
image: example:latest
طبّق وأعد المحاولة:
kubectl apply -f deployment.yaml
لـ taints مخصصة، يسري نفس الأسلوب:
# تحقق من taint
kubectl describe node <node-name> | grep Taint
# مثال: my-taint=myvalue:NoSchedule
# أضف toleration مطابق
tolerations:
- key: "my-taint"
operator: "Equal"
value: "myvalue"
effect: "NoSchedule"
4. PersistentVolumeClaim (PVC) pending
تحقق إذا كان PVC موجود وملزوم:
kubectl get pvc
# الإخراج:
# NAME STATUS VOLUME CAPACITY ACCESS MODES
# my-pvc Pending <none> <none> RWO
إذا كان PVC pending، لا يمكنه الارتباط بأي PersistentVolume. تحقق السبب:
kubectl describe pvc <pvc-name>
الأسباب الشائعة:
– لا يوجد PV: أنشئ PV أو StorageClass.
– StorageClass لا يوجد: أنشئه أو تأكد من عنقود له واحد افتراضي.
أنشئ PersistentVolume:
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolume
metadata:
name: my-pv
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: /data
EOF
أو فعّل التوفير الديناميكي بإنشاء StorageClass:
cat <<EOF | kubectl apply -f -
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast
provisioner: kubernetes.io/host-path
EOF
ثم حدّث PVC لاستخدام هذا StorageClass:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
storageClassName: fast
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
طبّق و PVC يجب أن يلتزم:
kubectl apply -f pvc.yaml
kubectl get pvc # يجب أن تكون الآن Bound
5. Pod quota أو LimitRange تجاوزت
تحقق إذا كان namespace لديه resource quotas:
kubectl get resourcequota -n <namespace>
kubectl describe resourcequota <quota-name> -n <namespace>
مثال:
Name: cpu-quota
Namespace: default
Resource Used Hard
-------- ---- ----
cpu 1000m 2000m
memory 1Gi 2Gi
pods 5 10
pod الجديد قد يتجاوز quota. تحقق من طلبات pod:
kubectl get pod <pod-name> -o yaml | grep -A 5 "resources:"
الخيار أ: زد quota:
kubectl edit resourcequota <quota-name>
وزد قيم hard.
الخيار ب: قلل طلبات الموارد للـ pod:
resources:
requests:
cpu: "50m" # قلل
memory: "128Mi"
limits:
cpu: "200m"
memory: "256Mi"
تحقق أيضاً من قيود LimitRange:
kubectl get limitrange -n <namespace>
kubectl describe limitrange <limit-name>
LimitRange قد يفرض حدود أدنى أو قصوى. ضبّط pod ليناسب النطاق.
طبّق وأعد المحاولة:
kubectl apply -f deployment.yaml
6. Topology spread constraints أو pod anti-affinity
تحقق من مواصفات pod للـ topology spread أو anti-affinity:
kubectl get pod <pod-name> -o yaml | grep -A 15 "topologySpreadConstraints:\|affinity:"
مثال topology spread يتطلب 3 zones:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: example
إذا كان العنقود لديه فقط zone واحد أو لا عقد كافية لكل zone، pod لا يمكنه الجدولة. إما:
أ. أضف عقد عبر zones متعددة:
kubectl get nodes -o wide | grep "REGION\|ZONE"
ب. أرخِ القيد:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: ScheduleAnyway # تغيير من DoNotSchedule
أو أزل topology spread بالكامل إذا لم يكن مطلوباً.
طبّق وأعد المحاولة:
kubectl apply -f deployment.yaml
كيف تتجنبه
-
عيّن دائماً طلبات الموارد والحدود:
resources: requests: cpu: "100m" memory: "256Mi" limits: cpu: "500m" memory: "512Mi" -
راقب سعة العنقود:
kubectl top nodes kubectl describe node <node-name> | grep -A 10 "Allocated" -
استخدم node labels و selectors بحكمة، فقط عند الحاجة الحقيقية. تجنب الإفراط في تقييد pods.
-
افهم node taints قبل الجدولة:
kubectl describe node | grep Taint -
خطط لـ PVC provisioning: تأكد من وجود StorageClass أو PersistentVolumes قبل إنشاء pods تحتاجهم.
-
عيّن resource quotas معقولة للـ namespaces، لا ضيقة جداً:
kubectl get resourcequota -A -
استخدم cluster autoscaling لعناقيد السحابة لإضافة عقد عند pods pending:
# GKE, EKS, AKS, وغيرها توفر تكوين autoscaling
الأسئلة الشائعة
كيف أعرف لماذا pod عالق في Pending؟
شغّل kubectl describe pod <pod> وانظر إلى قسم Events. يظهر سبب الجدولة بالضبط، مثل ‘Insufficient cpu’ أو ‘node has a taint’.
ما الفرق بين Pending و FailedScheduling؟
Pending يعني الجدولة لم تعيّن pod لعقدة بعد. FailedScheduling حدث يشير لفشل محاولة جدولة. تحقق من kubectl describe pod لترى الأحداث.
كيف أرى CPU والذاكرة المتاحة على العقد؟
استخدم kubectl top nodes أو kubectl describe node لترى الموارد المخصصة/المتاحة. تحقق أيضاً من kubectl get nodes لترى حالة NotReady.
ما taints و tolerations، ولماذا تحجب pods؟
Taint يعلّم عقدة غير مناسبة لـ pods معينة. Toleration على pod يسمح له بالعمل على عقد مع taints. تحقق من kubectl describe node | grep Taint و tolerations في مواصفات pod.
كيف تم التحقق من هذا الدليل
كُتب يدويًا من الوثائق الرسمية، وأُعيد فحص كل أمر، ثم رُوجع مرة ثانية قبل النشر. آخر مراجعة في .
المصادر الرسمية التي قُرئت لهذا المقال

