
ImagePullBackOff signifie que le kubelet n’arrive pas à télécharger l’image
du conteneur depuis le registre. Le pod est assigné à un nœud (il n’est plus
Pending), mais la création du conteneur échoue car l’image est introuvable,
inaccessible ou refusée. Ce guide vous donne une méthodologie en 4 étapes
pour identifier la cause et débloquer le déploiement.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Comprendre la différence entre
ErrImagePulletImagePullBackOff - Identifier les 7 causes principales d’un échec de pull d’image
- Appliquer une méthodologie de diagnostic reproductible en 4 étapes
- Configurer
imagePullSecretspour un registre privé - Reproduire et résoudre un ImagePullBackOff sur un cluster de test
Prérequis
Section intitulée « Prérequis »- Un cluster Kubernetes fonctionnel (v1.28+)
kubectlconfiguré et connecté au cluster- Des droits de lecture sur les pods et événements
- Connaissances de base sur les Pods et les images de conteneurs
Qu’est-ce qu’un ImagePullBackOff ?
Section intitulée « Qu’est-ce qu’un ImagePullBackOff ? »Quand le kubelet essaie de télécharger une image et échoue, il passe par deux états successifs :
| État | Signification |
|---|---|
ErrImagePull | Le pull vient d’échouer — c’est la première tentative (ou une nouvelle tentative après un backoff) |
ImagePullBackOff | Le kubelet a déjà échoué et attend avant de réessayer — c’est le backoff exponentiel |
Ces deux états alternent en boucle : le kubelet essaie (ErrImagePull), échoue,
attend (ImagePullBackOff), puis réessaie. Le délai d’attente augmente
progressivement (backoff exponentiel), mais la documentation officielle
ne détaille pas les timings exacts de ce backoff aussi précisément que pour
CrashLoopBackOff.
Le processus de pull d’une image
Section intitulée « Le processus de pull d’une image »Quand le kubelet doit démarrer un conteneur, il suit ces étapes :
- Vérifier le cache local — l’image existe-t-elle déjà sur le nœud ?
- Résoudre le nom de l’image — ajouter
docker.io/library/si pas de registre explicite, et:latestsi pas de tag - S’authentifier — si un
imagePullSecretest configuré, le kubelet l’utilise pour s’authentifier auprès du registre - Télécharger l’image — pull des layers manquants
- Vérifier l’intégrité — validation du digest SHA256
Si une de ces étapes échoue, le kubelet émet un événement Failed avec le
détail de l’erreur, et le pod passe en ErrImagePull.
Les 7 causes principales
Section intitulée « Les 7 causes principales »| # | Cause | Message d’erreur typique | Où chercher |
|---|---|---|---|
| 1 | Tag ou nom d’image incorrect | manifest unknown, not found | kubectl describe pod → Events |
| 2 | Registre privé sans authentification | unauthorized, authentication required | kubectl describe pod → Events |
| 3 | imagePullSecret absent ou invalide | no basic auth credentials, unauthorized | kubectl describe pod → Events + kubectl get secret |
| 4 | Registre inaccessible (réseau) | dial tcp: i/o timeout, no such host | kubectl describe pod → Events |
| 5 | Limite de pull Docker Hub | toomanyrequests, rate limit exceeded | kubectl describe pod → Events |
| 6 | Image ou tag supprimé | manifest unknown, not found | kubectl describe pod → Events |
| 7 | Architecture incompatible | no matching manifest for linux/amd64 | kubectl describe pod → Events |
Méthodologie de diagnostic en 4 étapes
Section intitulée « Méthodologie de diagnostic en 4 étapes »-
Identifier les pods en ImagePullBackOff
Fenêtre de terminal kubectl get pods -A | grep -E 'ImagePull|ErrImage'Vous pouvez aussi filtrer les événements de type pull échoué :
Fenêtre de terminal kubectl get events -A --field-selector reason=Failed --sort-by='.lastTimestamp' | grep -i pullNotez le nom du pod, son namespace et depuis combien de temps il est dans cet état.
-
Lire le message d’erreur exact
Fenêtre de terminal kubectl describe pod <pod> -n <namespace>Allez directement à la section Events et cherchez les lignes
FailedouWarning. Le message contient l’information essentielle. Exemples :Failed to pull image "mon-registre.example.com/app:v2.1":rpc error: code = Unknown desc = failed to pull and unpack image:failed to resolve reference: pull access denied, repository does notexist or may require authorizationCe message vous dit : le registre est privé et le kubelet n’a pas les credentials.
Failed to pull image "nginx:v99":rpc error: code = NotFound desc = failed to pull and unpack image:failed to resolve reference: docker.io/library/nginx:v99:not foundCelui-ci : le tag
v99n’existe pas sur Docker Hub. -
Vérifier l’image et l’authentification
Vérifier que l’image existe :
Consultez l’interface ou l’API du registre concerné (Docker Hub, Harbor, GitLab Registry, ECR…) pour confirmer que le tag existe et qu’il est disponible pour l’architecture de vos nœuds. Pour tester un pull directement depuis un nœud, utilisez
crictl:Fenêtre de terminal # Tester le pull depuis le nœud (via un Pod de debug ou en SSH)crictl pull mon-registre.example.com/app:v2.1Vérifier l’imagePullSecret :
Fenêtre de terminal # Le secret existe-t-il dans le namespace du pod ?kubectl get secret -n <namespace> | grep docker# Le pod référence-t-il le secret ?kubectl get pod <pod> -n <namespace> -o jsonpath='{.spec.imagePullSecrets}'Si le pod n’a pas d’
imagePullSecretset que le registre est privé, c’est la cause du problème.Vérifier la connectivité réseau (depuis le contexte d’un nœud) :
kubectl debug node/crée un Pod de debug attaché au nœud cible. Depuis ce Pod, vous pouvez tester la résolution DNS et la connectivité réseau dans le contexte réseau du nœud :Fenêtre de terminal kubectl debug node/<node-name> -it --image=busybox:1.37# Une fois dans le shell du Pod de debug :nslookup mon-registre.example.comwget -q --spider https://mon-registre.example.com/v2/ && echo "OK" || echo "INACCESSIBLE" -
Corriger et vérifier
Selon la cause identifiée :
Cause Action corrective Tag incorrect Corriger le tag dans le manifeste (vérifier sur le registre) Registre privé sans auth Créer un imagePullSecretet le référencer dans le podSecret invalide Recréer le secret avec les bons credentials Registre inaccessible Vérifier le DNS, le firewall, le proxy du nœud Rate limit Docker Hub Authentifier les pulls ou utiliser un mirror Image ou tag supprimé Corriger le tag ou rebuilder/repusher l’image Architecture incompatible Rebuilder l’image pour l’architecture cible ou utiliser un manifest multi-arch Après correction, le pod retente automatiquement le pull. Si vous souhaitez forcer un re-pull immédiat :
Fenêtre de terminal kubectl delete pod <pod> -n <namespace>Le contrôleur (Deployment, StatefulSet…) recréera un pod qui tentera le pull avec les nouveaux paramètres.
Configurer un imagePullSecret
Section intitulée « Configurer un imagePullSecret »L’une des causes les plus courantes est l’absence de credentials pour un registre privé. Voici la procédure complète :
Créer le secret
Section intitulée « Créer le secret »kubectl create secret docker-registry mon-registre-secret \ --docker-server=mon-registre.example.com \ --docker-username=mon-user \ --docker-password=mon-token \ --docker-email=admin@example.com \ -n <namespace>Référencer le secret dans le pod
Section intitulée « Référencer le secret dans le pod »apiVersion: v1kind: Podmetadata: name: app-priveespec: imagePullSecrets: - name: mon-registre-secret containers: - name: app image: mon-registre.example.com/app:v2.1Automatiser avec le ServiceAccount
Section intitulée « Automatiser avec le ServiceAccount »Pour éviter d’ajouter imagePullSecrets dans chaque pod, associez le secret
au ServiceAccount par défaut du namespace :
kubectl patch serviceaccount default -n <namespace> \ -p '{"imagePullSecrets": [{"name": "mon-registre-secret"}]}'Tous les pods du namespace utilisant le ServiceAccount default hériteront
automatiquement du secret.
Exemples pratiques : reproduire un ImagePullBackOff
Section intitulée « Exemples pratiques : reproduire un ImagePullBackOff »Cas 1 : tag inexistant
Section intitulée « Cas 1 : tag inexistant »kubectl apply -f- <<'EOF'apiVersion: v1kind: Podmetadata: name: pull-bad-tag namespace: defaultspec: containers: - name: app image: nginx:version-inexistanteEOFDiagnostic :
kubectl describe pod pull-bad-tag | tail -10Vous verrez Failed to pull image "nginx:version-inexistante" avec
not found.
Cas 2 : registre privé sans credentials
Section intitulée « Cas 2 : registre privé sans credentials »kubectl apply -f- <<'EOF'apiVersion: v1kind: Podmetadata: name: pull-no-auth namespace: defaultspec: containers: - name: app image: mon-registre-prive.example.com/app:latestEOFDiagnostic :
kubectl describe pod pull-no-auth | tail -10Le message indiquera unauthorized ou authentication required.
Cas 3 : nom d’image mal formé
Section intitulée « Cas 3 : nom d’image mal formé »kubectl apply -f- <<'EOF'apiVersion: v1kind: Podmetadata: name: pull-bad-name namespace: defaultspec: containers: - name: app image: "nginx ::latest"EOFDiagnostic :
kubectl describe pod pull-bad-name | tail -10Le message indiquera une erreur de résolution de référence avec un nom d’image invalide.
Nettoyage
Section intitulée « Nettoyage »kubectl delete pod pull-bad-tag pull-no-auth pull-bad-name --force --grace-period=0 2>/dev/nullCas particuliers
Section intitulée « Cas particuliers »ImagePullBackOff sur un seul nœud
Section intitulée « ImagePullBackOff sur un seul nœud »Si certains pods démarrent normalement et d’autres pas, le problème est probablement local au nœud :
- Le nœud n’a pas de connectivité réseau vers le registre (proxy manquant, DNS défaillant)
- Le disque du nœud est plein (plus de place pour stocker les layers)
- Le runtime de conteneur a un problème de configuration (containerd, CRI-O)
Ouvrez une session de debug sur le nœud affecté avec kubectl debug node/<node-name> puis vérifiez la résolution DNS, la connectivité réseau
vers le registre et l’état du runtime CRI. Pour l’inspection du runtime,
utilisez crictl :
# Session de debug interactive sur le nœudkubectl debug node/<node-name> -it --image=busybox:1.37# Depuis le pod de debug, testez la connectiviténslookup mon-registre.example.com# Sur le nœud (SSH ou debug), inspecter le runtimecrictl infocrictl images | grep mon-imageRate limit Docker Hub
Section intitulée « Rate limit Docker Hub »Docker Hub applique des limites de pull sur une fenêtre glissante de 6 heures. Les usages non authentifiés et certains comptes non payants peuvent être limités, tandis que les abonnements payants n’ont pas de limite de pull documentée. Dans un cluster avec plusieurs nœuds partageant la même IP publique, ces limites sont vite atteintes.
Le message d’erreur contient toomanyrequests :
toomanyrequests: You have reached your pull rate limit.You may increase the limit by authenticating and upgrading:https://www.docker.com/increase-rate-limitSolutions :
- Authentifier les pulls avec un compte Docker Hub pour bénéficier d’une limite plus élevée
- Mettre en place un registry mirror (Harbor, Nexus, registry:2)
- Utiliser
imagePullPolicy: IfNotPresentpour éviter les pulls inutiles
ImagePullBackOff après un upgrade de cluster
Section intitulée « ImagePullBackOff après un upgrade de cluster »Si un upgrade de cluster change le runtime de conteneur (par exemple de Docker à containerd), le cache d’images local est peut-être perdu. Tous les pods doivent re-puller leurs images, ce qui peut provoquer des ImagePullBackOff simultanés si le registre ou le réseau ne tient pas la charge.
Dépannage rapide
Section intitulée « Dépannage rapide »| Symptôme | Première action | Commande |
|---|---|---|
ImagePullBackOff + not found | Vérifier le tag | kubectl describe pod <pod> → chercher le nom exact de l’image |
ImagePullBackOff + unauthorized | Vérifier l’imagePullSecret | kubectl get pod <pod> -o jsonpath='{.spec.imagePullSecrets}' |
ImagePullBackOff + i/o timeout | Problème réseau | Tester la connectivité depuis le nœud vers le registre |
ImagePullBackOff + toomanyrequests | Rate limit Docker Hub | Authentifier les pulls ou mettre en place un mirror |
ErrImageNeverPull | imagePullPolicy: Never mais image absente | Changer la policy ou pré-charger l’image sur le nœud |
| Un seul nœud en erreur | Problème local au nœud | Vérifier disque, DNS, proxy et runtime du nœud |
À retenir
Section intitulée « À retenir »ErrImagePullest l’erreur immédiate,ImagePullBackOffest l’attente entre deux tentatives — les deux apparaissent en alternancekubectl describe podest la commande clé — le message d’erreur dans les Events contient la raison exacte de l’échec- Le tag
:latestest un piège : s’il est supprimé du registre, les nouveaux pods échouent alors que les anciens continuent de fonctionner. Utilisez des tags explicites - Pour un registre privé, il faut un
imagePullSecretdans le même namespace que le pod — pensez à l’associer au ServiceAccount pour ne pas l’oublier - Docker Hub a un rate limit sur une fenêtre de 6 h — authentifiez vos pulls ou utilisez un mirror local en production
- Si le problème ne touche qu’un seul nœud, c’est probablement un souci réseau, disque ou runtime local
- Après correction, le kubelet retente le pull automatiquement — si vous voulez forcer un retry immédiat, supprimez le pod