O que significa
Para subir um container, o kubelet do nó pede a imagem ao runtime (containerd ou CRI-O), que a baixa do registry. Quando o download falha, o container fica em Waiting com Reason: ErrImagePull. O kubelet tenta de novo com intervalo crescente e, enquanto espera, o motivo passa a ser ImagePullBackOff. Os dois alternam no get pods conforme o momento em que você olha.
O intervalo cresce até um limite fixo de 300 segundos (5 minutos), definido na documentação do Kubernetes, página "Images", seção "ImagePullBackOff". Ou seja: depois de corrigir a causa, o pod pode levar alguns minutos para tentar de novo sozinho. Apagar o pod (o Deployment cria outro) ou fazer um rollout restart antecipa a tentativa.
O RESTARTS fica em 0 o tempo todo, e isso é o que separa este erro de um CrashLoopBackOff: aqui o container nunca rodou.
Causas comuns
Um caractere trocado na tag basta. O registry responde que a referência não existe e o kubelet tenta de novo, sem sucesso, até alguém corrigir o manifesto.
O nó não resolve o nome do registry ou não chega até ele: DNS interno que só existe na rede do escritório, firewall de saída, registry privado atrás de VPN.
O registry existe e a imagem também, mas o nó não se autentica: falta o imagePullSecrets no pod, a identidade do nó não tem permissão de leitura, ou a credencial expirou.
Registries públicos limitam downloads anônimos. Em clusters que sobem muitos nós ao mesmo tempo, o limite chega antes do fim do deploy.
A imagem existe só para amd64 e o nó é arm64 (ou o contrário). Comum ao misturar pools de nós Graviton ou Ampere com imagens construídas numa máquina x86.
Diagnóstico em 3 comandos
As saídas abaixo são reais, de dois pods de teste: vitrine, com a tag digitada errado, e catalogo, apontando para um registry que o nó não resolve.
1 · veja o estado
kubectl -n loja get pods NAME READY STATUS RESTARTS AGE
catalogo 0/1 ErrImagePull 0 109s
vitrine 0/1 ErrImagePull 0 109s Os dois estavam em ErrImagePull nesse instante; segundos depois, no describe, o catalogo já aparecia como ImagePullBackOff, esperando a próxima tentativa.
2 · leia a mensagem do evento Failed
kubectl -n loja describe pod vitrine | sed -n '/Events:/,$p' Events:
Type Reason From Message
Warning Failed kubelet Failed to pull image "nginx:1.27-alpnie": rpc error: code = NotFound
desc = failed to pull and unpack image "docker.io/library/nginx:1.27-alpnie":
failed to resolve reference "docker.io/library/nginx:1.27-alpnie":
docker.io/library/nginx:1.27-alpnie: not found
Warning Failed kubelet Error: ErrImagePull
Normal BackOff kubelet Back-off pulling image "nginx:1.27-alpnie"
Warning Failed kubelet Error: ImagePullBackOff A última palavra da mensagem diz a causa. not found: o registry respondeu, e a referência não existe. No outro pod, o pedido nem saiu do nó:
kubectl -n loja describe pod catalogo | grep "Failed to pull" Failed to pull image "registry.loja.internal/catalogo:2.3.1": ... failed to do request:
Head "https://registry.loja.internal/v2/catalogo/manifests/2.3.1":
dial tcp: lookup registry.loja.internal: no such host Com registry privado sem credencial, a mesma linha termina em unauthorized ou em código 401 ou 403.
3 · confira a referência exata que o pod está usando
kubectl -n loja get pod vitrine -o jsonpath='{.spec.containers[*].image}{"\n"}' nginx:1.27-alpnie A correção
Tag ou nome errado: corrija no manifesto (ou no values do Helm) e aplique. Prefira tags imutáveis de versão, ou o digest, a latest: com latest o mesmo manifesto pode puxar imagens diferentes em nós diferentes.
Registry inalcançável: o problema é de rede do nó, não do Kubernetes. Teste a resolução e a conexão a partir de um pod no mesmo nó, e libere DNS e saída para o registry.
Registry privado: crie um Secret do tipo kubernetes.io/dockerconfigjson e referencie no pod (documentação do Kubernetes, "Images", seção "Specifying imagePullSecrets on a Pod").
kubectl -n loja create secret docker-registry registry-loja \
--docker-server=registry.loja.internal \
--docker-username=deploy \
--docker-password="$REGISTRY_TOKEN" spec:
imagePullSecrets:
- name: registry-loja
containers:
- name: catalogo
image: registry.loja.internal/catalogo:2.3.1 No AKS e no EKS
AKS com ACR: em vez de Secret, dê à identidade do pool de nós o papel AcrPull no registry. O comando az aks update -n CLUSTER -g GRUPO --attach-acr REGISTRY faz essa atribuição. A Microsoft avisa que registries com ABAC habilitado precisam do papel "Container Registry Repository Reader" em vez do AcrPull, e que atribuir o papel por grupo do Entra ID pode demorar a valer (documentação "Authenticate with ACR from AKS").
EKS com ECR: nos nós gerenciados e autogerenciados, quem baixa a imagem é o papel IAM do nó (NodeInstanceRole), que precisa das permissões de leitura do ECR, como ecr:BatchGetImage e ecr:BatchCheckLayerAvailability (documentação "Using Amazon ECR images with Amazon EKS").
avisoNos dois casos, uma imagem de outra conta ou outra assinatura não vem junto com a permissão do cluster. Se o registry é de outra conta, a permissão tem de ser dada lá.
Como aparece no Kubepier
O Kubepier mostra os eventos do pod com os avisos primeiro, com filtro por tipo, namespace e motivo. O diagnóstico por IA explica o erro a partir dos eventos e do log, em português, com a sua chave de API (Anthropic ou OpenAI). Abaixo, uma ilustração com dados fictícios.
Causa provável: o nó não resolve registry.loja.internal. Evidência: o evento Failed traz "dial tcp: lookup registry.loja.internal: no such host". Não é credencial nem tag: o pedido nem chegou ao registry. Correção sugerida: usar o endereço público do registry ou liberar o DNS interno para os nós do cluster.