ImagePullBackOff يعني Kubernetes حاول تحميل صورة الحاوية ولكن فشل. ينتظر pod، يعيد المحاولة، ويفشل مرة أخرى في حلقة exponential backoff. يوضح هذا الدليل كيفية تشخيص وإصلاح الأسباب الأكثر شيوعاً.

الأعراض

حالة pod تظهر ImagePullBackOff. تشغيل kubectl describe pod يكشف:

Name:           example-app-5f7c9d4bfb-7x8kq
Namespace:      default
Status:         Pending
Events:
  Type     Reason             Age    Message
  ----     ------             ----   -------
  Normal   Pulling            2m15s  Pulling image "example:latest"
  Warning  Failed             2m12s  Failed to pull image "example:latest":
           rpc error: code = Unknown desc = Error response from daemon: manifest not found
  Warning  Failed             2m8s   Failed to pull image "example:latest": rpc error: code = Unknown desc = Error response from daemon: manifest not found
  Normal   BackOff            115s   Back-off pulling image "example:latest"

لماذا يحدث

مرتبة حسب الاحتمالية:

  1. اسم صورة أو وسم خاطئ — الصورة لا تكون موجودة في التسجيل. خطأ في الاسم، الوسم غير موجود، أو الصورة لم تُدفع.
  2. تسجيل خاص بدون imagePullSecrets — Kubernetes لا يستطيع المصادقة على التسجيل ويتم رفضه برسالة “unauthorized” أو “authentication required”.
  3. حد معدل Docker Hub مصاب — السحب غير المصرح من Docker Hub محدود. بعد 100 سحبة لكل 6 ساعات، يفشل السحب الجديد.
  4. معمارية أو نظام تشغيل خاطئ — الصورة مبنية لمعمارية CPU مختلفة (مثل arm64 مقابل amd64) أو نظام تشغيل، والتشغيل لا يستطيع تنفيذها.
  5. التسجيل معطل أو بعيد أو محجوب — سياسة الشبكة، جدار حماية، DNS، أو خادم التسجيل نفسه معطل أو غير مهيأ.
  6. بيانات الاعتماد منتهية الصلاحية أو غير صحيحة — بيانات اعتماد التسجيل في Secret تغيرت أو انتهت صلاحية الرمز.

الحل

1. اسم صورة أو وسم خاطئ

تحقق مما حددته:

kubectl get pod <pod-name> -o yaml | grep -A 2 "image:"

تحقق من وجود الصورة في التسجيل:

# لـ Docker Hub
docker pull example:latest

# لتسجيل خاص
docker pull registry.example.com/example:latest

# إذا فشل السحب محلياً، سيفشل في Kubernetes أيضاً

إذا لم توجد الصورة، ادفعها أولاً:

# ابنِ الصورة
docker build -t example:latest .

# وسمها لتسجيلك
docker tag example:latest registry.example.com/example:latest

# ادفعها
docker push registry.example.com/example:latest

ثم حدّث Deployment لاستخدام الصورة الصحيحة:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: example-app
spec:
  template:
    spec:
      containers:
      - name: app
        image: registry.example.com/example:v1.0.0    # صورة صحيحة

طبّق وأعد المحاولة:

kubectl apply -f deployment.yaml
kubectl rollout restart deployment/example-app

2. تسجيل خاص بدون imagePullSecrets

إذا كان التسجيل خاص، يحتاج Kubernetes لبيانات الاعتماد. أنشئ docker-registry Secret:

kubectl create secret docker-registry myregistrycred \
  --docker-server=registry.example.com \
  --docker-username=myuser \
  --docker-password=mypass \
  --docker-email=me@example.com \
  --namespace=default

أو من تكوين docker login:

# إذا كنت قد سجلت محلياً بالفعل، انسخ بيانات الاعتماد
kubectl create secret generic myregistrycred \
  --from-file=.dockerconfigjson=$HOME/.docker/config.json \
  --type=kubernetes.io/dockercfg

تحقق من إنشاء Secret:

kubectl get secret myregistrycred -o yaml

ثم اجعل مرجع له في مواصفات pod:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: example-app
spec:
  template:
    spec:
      imagePullSecrets:
      - name: myregistrycred
      containers:
      - name: app
        image: registry.example.com/example:latest

بدلاً من ذلك، أضف Secret لحساب الخدمة بحيث تستخدمه جميع pods:

kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "myregistrycred"}]}'

تحقق:

kubectl get serviceaccount default -o yaml

ثم احذف وأنشئ من جديد pod لسحب السر الجديد:

kubectl delete pod <pod-name>

3. حد معدل Docker Hub مصاب

إذا كنت تسحب بدون مصادقة من Docker Hub، فقد وصلت لحد 100 سحبة لكل 6 ساعات. صادق بدلاً من ذلك:

أنشئ Docker Hub Personal Access Token (أو استخدم كلمة المرور) وأنشئ Secret:

kubectl create secret docker-registry dockerhubcred \
  --docker-server=docker.io \
  --docker-username=myusername \
  --docker-password=dckr_pat_XXXXXXX \
  --docker-email=me@example.com

حدّث Deployment لجعل مرجع له:

imagePullSecrets:
- name: dockerhubcred

أو أضفه لحساب الخدمة الافتراضي:

kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "dockerhubcred"}]}'

للحدود أعلى، استخدم حساب Docker Hub مدفوع أو تسجيل خاص. احذف وأنشئ pods من جديد لإعادة المحاولة مع بيانات الاعتماد الجديدة:

kubectl delete pod <pod-name>

4. معمارية أو نظام تشغيل خاطئ

الصورة مبنية لمعمارية CPU أو نظام تشغيل مختلف. تحقق من معمارية العقدة:

kubectl get nodes -o wide | grep -i arch
# أو:
kubectl describe node <node-name> | grep "kubernetes.io/arch"

تحقق من معمارية الصورة. ابنها لمعمارية صحيحة باستخدام Docker BuildX:

# ابنِ لمعماريات متعددة
docker buildx build --platform linux/amd64,linux/arm64 \
  -t registry.example.com/example:latest \
  --push .

# أو ابنِ فقط للهدف
docker buildx build --platform linux/arm64 \
  -t registry.example.com/example:arm64 .

يمكنك أيضاً استخدام صورة أساسية متعددة المعماريات:

FROM node:20-alpine    # يدعم بالفعل amd64, arm64, إلخ
COPY . /app
WORKDIR /app
CMD ["node", "server.js"]

إذا كانت الصورة مبنية بالفعل لمعمارية خاطئة، أعد بناءها أو استخدم صورة أساسية مختلفة.

5. التسجيل معطل أو بعيد أو محجوب

اختبر اتصال الشبكة للتسجيل:

# من العنقود
kubectl run debug --image=busybox -it --rm -- sh
# داخل الحاوية:
wget https://registry.example.com
nc -zv registry.example.com 443

تحقق من قرار DNS:

kubectl run debug --image=busybox -it --rm -- sh
# داخل:
nslookup registry.example.com

تحقق من سياسات الشبكة التي قد تحجب egress:

kubectl get networkpolicy -A

تحقق من قواعد جدار حماية العنقود. إذا كان التسجيل داخل العنقود (مثل instance Harbor خاص)، تأكد من:
– pod التسجيل يعمل: kubectl get pod -n registry
– خدمة التسجيل يمكن الوصول إليها: kubectl get svc -n registry

انتظر عودة التسجيل، ثم احذف pod لإعادة المحاولة:

kubectl delete pod <pod-name>

6. بيانات الاعتماد منتهية الصلاحية أو غير صحيحة

إذا حدثت بيانات الاعتماد في التسجيل الخاص، حدّث Secret في Kubernetes:

# احذف Secret القديم
kubectl delete secret myregistrycred

# أنشئ واحد جديد مع بيانات اعتماد محدثة
kubectl create secret docker-registry myregistrycred \
  --docker-server=registry.example.com \
  --docker-username=myuser \
  --docker-password=mynewpass \
  --docker-email=me@example.com

أجبر pods على إعادة المصادقة بحذفها:

kubectl delete pod <pod-name>

للمصادقة المستندة لرمز (مثل رموز حساب الخدمة Kubernetes المستخدمة بواسطة التسجيلات داخل العنقود)، أنشئ الرمز من جديد وحدّث Secret.

كيف تتجنبه

  1. ادفع الصورة قبل النشر:

    docker build -t registry.example.com/app:v1.0.0 .
    docker push registry.example.com/app:v1.0.0
    # ثم انشر مع هذا الوسم الدقيق
    

  2. استخدم وسوم محددة، وليس latest:

    image: registry.example.com/app:v1.2.3    # جيد
    image: registry.example.com/app:latest    # محفوف بالمخاطر
    

  3. صادق التسجيلات الخاصة:

    kubectl create secret docker-registry myregistrycred ...
    # واستخدمه في جميع Deployments
    

  4. سحب مسبق الصور على العقد باستخدام DaemonSets للصور المستخدمة بكثرة، مما يقلل وقت السحب والفشل.

  5. استخدم مرآة التسجيل الخاص أو ذاكرة تخزين مؤقت (مثل Harbor، Artifactory) لتقليل الاعتماد على حدود معدل Docker Hub.

  6. اختبر سحب الصورة قبل الالتزام بـ Kubernetes:

    docker run --rm registry.example.com/app:v1.0.0 /bin/sh -c "echo 'works'"
    

الأسئلة الشائعة

كيف أتحقق من سبب فشل سحب الصورة؟

شغّل kubectl describe pod <pod-name> وانظر إلى قسم Events. يظهر خطأ التسجيل بالضبط، مثل ‘not found’ أو ‘authentication required’.

ما الفرق بين ImagePullBackOff و CrashLoopBackOff؟

ImagePullBackOff يعني فشل تنزيل الصورة قبل بدء الحاوية حتى. CrashLoopBackOff يعني الحاوية بدأت ولكن انهارت. تحقق من kubectl describe pod لترى أيهما لديك.

كيف أستخدم تسجيل Docker خاص في Kubernetes؟

أنشئ docker-registry Secret، ثم اجعل مرجع له في imagePullSecrets في مواصفات pod أو حساب الخدمة. اعرض أمر kubectl create secret مع بيانات اعتماد التسجيل.

لماذا يفشل السحب من Docker Hub أحياناً؟

Docker Hub له حدود معدل: 100 سحبة لكل 6 ساعات للمستخدمين غير المصرح، 200 لكل 6 ساعات للحسابات المجانية. بعد الوصول للحد، يفشل السحب برسالة ‘Too Many Requests’. صادق بحساب Docker Hub أو استخدم تسجيل خاص.

كيف تم التحقق من هذا الدليل

كُتب يدويًا من الوثائق الرسمية، وأُعيد فحص كل أمر، ثم رُوجع مرة ثانية قبل النشر. آخر مراجعة في .

المصادر الرسمية التي قُرئت لهذا المقال

شاركها.

التعليقات مغلقة.