Veröffentlicht am

Kubernetes ImagePullBackOff lösen: Ursachen und Fixes

Teilen:
Authors

TL;DR

  • ImagePullBackOff bedeutet, dass Kubernetes das Container-Image nicht herunterladen kann -- kubectl describe pod zeigt die genaue Ursache in den Events
  • 8 haeufigste Ursachen: Image existiert nicht, Registry-Auth fehlt, kein HTTPS, falscher Tag, Netzwerk-Problem, Rate Limiting, falsche Architektur, Digest Mismatch
  • Schnellste Loesung: imagePullSecret erstellen und im Pod oder ServiceAccount referenzieren
  • Best Practices: Immer spezifische Tags statt latest verwenden, vollstaendige Image-Namen mit Registry angeben
  • Docker Hub Rate Limits (100 Pulls/6h anonym) umgehen durch Login-Secret oder alternatives Registry wie ghcr.io

Kubernetes ImagePullBackOff - Kompletter Troubleshooting Guide

ImagePullBackOff und ErrImagePull bedeuten, dass Kubernetes das Container-Image nicht herunterladen kann. Dieser Guide zeigt alle Ursachen und die konkreten Lösungen.

Was bedeuten diese Status?

NAME        READY   STATUS             RESTARTS   AGE
my-pod      0/1     ImagePullBackOff   0          2m
StatusBedeutung
ErrImagePullErster fehlgeschlagener Pull-Versuch
ImagePullBackOffWiederholte Fehlversuche (Backoff-Timer)

Kubernetes versucht erneut mit exponential Backoff: 10s → 20s → 40s → ... → 5min.


Schnelle Diagnose

# 1. Fehlerdetails anzeigen
kubectl describe pod <pod-name>

# 2. Events filtern
kubectl get events --field-selector reason=Failed

# 3. Image-Name prüfen
kubectl get pod <pod-name> -o jsonpath='{.spec.containers[0].image}'

Die Events-Sektion in kubectl describe zeigt die genaue Ursache!


Die 8 häufigsten Ursachen

1. Image existiert nicht

Symptom:

Failed to pull image "nginx:v999":
rpc error: code = NotFound desc = failed to pull and unpack image:
not found

Diagnose:

# Image lokal testen
docker pull nginx:v999
# Error: manifest for nginx:v999 not found

# Verfügbare Tags prüfen
# Docker Hub: hub.docker.com/_/nginx
# oder mit crane/skopeo:
crane ls nginx | head -20

Lösung:

# Korrekten Tag verwenden
spec:
  containers:
  - name: nginx
    image: nginx:1.25-alpine  # Existierender Tag

Tipp: Immer spezifische Tags verwenden, nie nur latest!


2. Registry-Authentifizierung fehlt

Symptom:

Failed to pull image "myregistry.io/app:v1":
rpc error: code = Unknown desc = failed to pull and unpack image:
pull access denied, repository does not exist or may require authorization

Diagnose:

# Ist ein imagePullSecret konfiguriert?
kubectl get pod <pod-name> -o yaml | grep -A 3 imagePullSecrets

# Existiert das Secret?
kubectl get secrets

Lösung:

# 1. Registry Secret erstellen
kubectl create secret docker-registry regcred \
  --docker-server=myregistry.io \
  --docker-username=myuser \
  --docker-password=mypassword \
  --docker-email=user@example.com

# 2. Im Pod referenzieren
spec:
  imagePullSecrets:
  - name: regcred
  containers:
  - name: app
    image: myregistry.io/app:v1

Für ServiceAccount (alle Pods automatisch):

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

3. Private Registry ohne HTTPS

Symptom:

Failed to pull image "192.168.1.100:5000/app:v1":
http: server gave HTTP response to HTTPS client

Lösung A: containerd konfigurieren

# /etc/containerd/config.toml auf jedem Node
[plugins."io.containerd.grpc.v1.cri".registry]
  [plugins."io.containerd.grpc.v1.cri".registry.mirrors]
    [plugins."io.containerd.grpc.v1.cri".registry.mirrors."192.168.1.100:5000"]
      endpoint = ["http://192.168.1.100:5000"]
  [plugins."io.containerd.grpc.v1.cri".registry.configs]
    [plugins."io.containerd.grpc.v1.cri".registry.configs."192.168.1.100:5000".tls]
      insecure_skip_verify = true
systemctl restart containerd

Lösung B: HTTPS für Registry einrichten (empfohlen für Production)


4. Image Tag fehlt/ist falsch

Symptom:

Failed to pull image "myapp":
rpc error: code = NotFound desc = failed to resolve reference "docker.io/library/myapp:latest"

Diagnose:

# Vollständiger Image-Name prüfen
kubectl get pod <pod-name> -o jsonpath='{.spec.containers[0].image}'

# Ergibt: myapp
# Wird interpretiert als: docker.io/library/myapp:latest

Lösung:

# Vollständigen Image-Namen verwenden
spec:
  containers:
  - name: app
    image: ghcr.io/myorg/myapp:v1.2.3  # Registry + Org + Image + Tag

5. Netzwerk-Problem zur Registry

Symptom:

Failed to pull image:
rpc error: code = Unknown desc = failed to pull and unpack image:
dial tcp: lookup registry.example.com: no such host

Diagnose:

# DNS testen vom Node
kubectl run debug --rm -it --image=busybox -- nslookup registry.example.com

# Verbindung testen
kubectl run debug --rm -it --image=busybox -- wget -O- https://registry.example.com/v2/

Lösungen:

  1. DNS prüfen: CoreDNS funktioniert?
  2. Firewall: Outbound zu Registry erlaubt?
  3. Proxy: HTTP_PROXY konfiguriert?
# Für Nodes hinter Proxy
env:
- name: HTTP_PROXY
  value: "http://proxy.company.com:8080"
- name: HTTPS_PROXY
  value: "http://proxy.company.com:8080"
- name: NO_PROXY
  value: "10.0.0.0/8,172.16.0.0/12,192.168.0.0/16"

6. Rate Limiting (Docker Hub)

Symptom:

Failed to pull image "nginx:latest":
rpc error: code = Unknown desc = failed to pull and unpack image:
toomanyrequests: You have reached your pull rate limit.

Docker Hub Limits:

  • Anonym: 100 Pulls / 6 Stunden
  • Free Account: 200 Pulls / 6 Stunden
  • Pro/Team: Mehr

Lösungen:

# 1. Docker Hub Login verwenden
kubectl create secret docker-registry dockerhub \
  --docker-server=docker.io \
  --docker-username=<user> \
  --docker-password=<token>
# 2. Alternatives Registry (ghcr.io, quay.io)
image: ghcr.io/nginx/nginx:1.25

# 3. Image lokal cachen
image: myregistry.io/mirrors/nginx:1.25

7. Image-Architektur stimmt nicht

Symptom:

Failed to pull image:
exec format error

Oder Pod startet, crasht aber sofort.

Diagnose:

# Image-Architektur prüfen
docker manifest inspect nginx:1.25 | jq '.manifests[].platform'

Ursache: AMD64 Image auf ARM Node (oder umgekehrt).

Lösung:

# Multi-Arch Image verwenden
image: nginx:1.25-alpine  # Unterstützt amd64 + arm64

# Oder Node-Selector
spec:
  nodeSelector:
    kubernetes.io/arch: amd64

8. Digest Mismatch

Symptom:

Failed to pull image:
digest did not match

Ursache: Image wurde in Registry überschrieben, aber Node hat alte Version gecached.

Lösung:

# imagePullPolicy: Always erzwingt neuen Pull
spec:
  containers:
  - name: app
    image: myapp:v1
    imagePullPolicy: Always

Oder Image mit Digest statt Tag referenzieren:

image: myapp@sha256:abc123def456...

Registry Secrets Best Practices

Secret pro Namespace

# Secret in jedem Namespace erstellen
for ns in default production staging; do
  kubectl create secret docker-registry regcred \
    --docker-server=myregistry.io \
    --docker-username=user \
    --docker-password=pass \
    -n $ns
done

ServiceAccount automatisch patchen

# service-account.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: default
  namespace: production
imagePullSecrets:
- name: regcred

Mit Helm

# values.yaml
image:
  repository: myregistry.io/app
  tag: v1.2.3
  pullSecrets:
    - name: regcred

Debugging-Workflow

┌──────────────────────────────────────┐
│ kubectl describe pod <name>│ → Events Sektion lesen               │
└─────────────────┬────────────────────┘
       ┌──────────▼──────────┐
Fehler-Typ?       └──────────┬──────────┘
    ┌─────────────┼─────────────┬─────────────┐
    │             │             │             │
┌───▼───┐    ┌────▼────┐   ┌────▼────┐   ┌────▼────┐
│not    │    │access   │   │timeout  │   │rate     │
│found  │    │denied   │   │         │   │limit    │
└───┬───┘    └────┬────┘   └────┬────┘   └────┬────┘
    │             │             │             │
    ▼             ▼             ▼             ▼
Tag prüfen   Secret       Netzwerk      Registry
             erstellen    prüfen        wechseln

Automatisiertes Debug-Skript

#!/bin/bash
# image-pull-debug.sh

POD=$1
NS=${2:-default}

echo "=== Pod Image Info ==="
IMAGE=$(kubectl get pod $POD -n $NS -o jsonpath='{.spec.containers[0].image}')
echo "Image: $IMAGE"

echo -e "\n=== Pod Status ==="
kubectl get pod $POD -n $NS

echo -e "\n=== Image Pull Events ==="
kubectl get events -n $NS --field-selector involvedObject.name=$POD | grep -i "pull\|image"

echo -e "\n=== ImagePullSecrets ==="
kubectl get pod $POD -n $NS -o jsonpath='{.spec.imagePullSecrets}' | jq .

echo -e "\n=== Test Image Pull (from debug pod) ==="
echo "Run manually: kubectl run debug --rm -it --image=busybox -- wget -O- <registry>/v2/"

Häufige Fehler vermeiden

1. Nie latest Tag verwenden

# SCHLECHT
image: nginx:latest

# GUT
image: nginx:1.25.3-alpine

2. Immer vollständigen Namen

# SCHLECHT (wird zu docker.io/library/myapp:latest)
image: myapp

# GUT
image: ghcr.io/myorg/myapp:v1.2.3

3. imagePullPolicy beachten

TagDefault PolicyVerhalten
:latestAlwaysImmer Pull
:v1.2.3IfNotPresentNur wenn nicht lokal
@sha256:...IfNotPresentNur wenn nicht lokal

CKA-Prüfungstipp

ImagePullBackOff ist ein häufiges Prüfungsthema:

  1. kubectl describe pod → Events lesen
  2. Secret für private Registry erstellen
  3. imagePullSecrets im Pod konfigurieren
# Schnell-Lösung in der Prüfung
kubectl create secret docker-registry regcred \
  --docker-server=<url> \
  --docker-username=<user> \
  --docker-password=<pass>

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

Mehr: CKA Zertifizierung Guide


Zusammenfassung

FehlerUrsacheLösung
not foundImage/Tag existiert nichtTag prüfen
access deniedAuth fehltimagePullSecret
HTTP responseInsecure Registrycontainerd config
no such hostDNS/NetzwerkFirewall/DNS prüfen
toomanyrequestsRate LimitLogin oder Mirror
exec formatFalsche ArchitekturMulti-Arch Image
digest mismatchCache veraltetimagePullPolicy: Always

Wichtigster Tipp: Immer kubectl describe pod ausführen und die Events-Sektion lesen!


Dieser Troubleshooting-Guide wird regelmäßig aktualisiert. Letzte Aktualisierung: Januar 2026.

Kubernetes-Beratung gesucht?

Wir helfen deutschen Unternehmen bei der Kubernetes-Implementierung, Migration und Optimierung. DSGVO-konform und praxiserprobt.

📖 Verwandte Artikel

Weitere interessante Beiträge zu ähnlichen Themen