ImagePullBackOff bedeutet, dass der kubelet das Container-Image für deinen Pod nicht ziehen konnte und jetzt mit wachsender Pause auf den nächsten Versuch wartet. Der Container startet gar nicht erst. Die Ursache steht fast immer in den Events von kubectl describe pod, in der Meldung „Failed to pull image“. Die häufigsten Gründe: falscher Image-Name oder Tag, private Registry ohne imagePullSecrets, das Pull-Limit von Docker Hub, Netzwerk oder DNS auf dem Node, ein Image ohne passende Prozessorarchitektur und ein Registry-Zertifikat, dem der Node nicht vertraut. ErrImagePull ist der einzelne gescheiterte Versuch, ImagePullBackOff die Wartezeit danach.
Ich betreibe seit 2017 Kubernetes-Cluster, heute vor allem k3s auf Hetzner Cloud, bin Kubestronaut der CNCF und habe das Kubernetes-Praxisbuch bei Rheinwerk geschrieben. Alle Beiträge zum Thema findest du auf der Seite Kubernetes.
Was ImagePullBackOff in Kubernetes bedeutet
Ein Container hat laut Kubernetes-Dokumentation drei mögliche Zustände: Waiting, Running und Terminated. Solange das Image fehlt, ist er im Zustand Waiting, und das Feld Reason sagt dir, warum, hier eben ImagePullBackOff. Der Pod bleibt in der Phase Pending, denn dazu zählt laut Dokumentation auch die Zeit, in der Images geladen werden. Mehr zu Phasen und Zuständen steht in Kubernetes Pod: was ist ein Pod?.
Anders als beim CrashLoopBackOff ist dein Code noch gar nicht gelaufen. Logs gibt es deshalb keine, kubectl logs hilft nicht. Die Antwort liegt in den Events.
ErrImagePull und ImagePullBackOff: der Unterschied
Beide Meldungen beschreiben dasselbe Problem zu zwei Zeitpunkten. Im Quellcode des kubelet ist ErrImagePull als allgemeiner Fehler beim Ziehen eines Images definiert, du siehst ihn direkt nach einem gescheiterten Versuch. Danach startet eine Wartezeit. Fragt der kubelet in dieser Zeit erneut nach dem Image, meldet er ImagePullBackOff und schreibt die Fehlermeldung des letzten Versuchs in das Feld Message des Containers, in kubectl describe pod unter State: Waiting. Deshalb wechselt die STATUS-Spalte von kubectl get pods zwischen beiden Werten.
Die Kubernetes-Dokumentation nennt als Obergrenze der Wartezeit 300 Sekunden, also 5 Minuten. Im Quellcode beginnt sie bei 10 Sekunden und verdoppelt sich mit jedem Fehlschlag. Ein Pod, der schon länger hängt, versucht es also nur noch alle paar Minuten.
Dazu kommen weitere Gründe aus derselben Familie:
Diagnose: kubectl describe und die Events lesen
Für die Diagnose reichen drei Befehle:
kubectl get pods -n shop
kubectl describe pod api-7d9c6b5f8-x2k4q -n shop
kubectl events --for pod/api-7d9c6b5f8-x2k4q -n shop
In kubectl describe pod steht im Abschnitt des Containers State: Waiting mit Reason: ImagePullBackOff. Ganz unten folgen die Events. Schematisch, gekürzt und mit einem Beispiel-Image sieht die Abfolge so aus:
Events:
Type Reason Message
---- ------ -------
Normal Pulling Pulling image "registry.example.com/shop/api:1.4.2"
Warning Failed Failed to pull image "registry.example.com/shop/api:1.4.2": <Fehler der Container-Laufzeit>
Warning Failed Error: ErrImagePull
Normal BackOff Back-off pulling image "registry.example.com/shop/api:1.4.2"
Warning Failed Error: ImagePullBackOff
Entscheidend ist der Text nach „Failed to pull image“: Dort steht, was die Container-Laufzeit von der Registry zurückbekommen hat, etwa ein unbekanntes Image, eine verweigerte Anmeldung, ein Zeitlimit oder ein Zertifikatsfehler. Ordne ihn einer der Ursachen unten zu. Weitere Befehle stehen in kubectl Befehle: die wichtigsten im Alltag.
Einen Punkt übersehen viele: Das Image zieht nicht dein Pod, sondern die Container-Laufzeit auf dem Node, zum Beispiel containerd, mit Netzwerk, DNS und Zertifikaten des Nodes. Ein Test aus einem anderen Pod sagt deshalb wenig. Mit Node-Zugang prüfst du direkt dort mit crictl pull <image>, meist mit Root-Rechten, in k3s als k3s crictl pull <image>. Für eine private Registry nutzt crictl das imagePullSecret nicht, du gibst die Zugangsdaten mit --creds <benutzer>:<token> mit, sonst scheitert der Test auch bei gesunder Registry. Ohne Node-Zugang ist docker pull <image> auf deinem Rechner der erste Test, den auch die Kubernetes-Dokumentation vorschlägt.
Die häufigsten Ursachen und ihr Fix
Falscher Image-Name oder Tag
Die Kubernetes-Dokumentation nennt ein gescheitertes Ziehen des Images als häufigste Ursache für Pods im Zustand Waiting und gibt drei Prüfpunkte vor: Stimmt der Name, wurde das Image gepusht, lässt es sich von Hand ziehen? Achte auf die stillen Ergänzungen: Aus busybox wird docker.io/library/busybox:latest. Fehlt der Registry-Teil, fragt Kubernetes also Docker Hub.
Für Produktion rät die Dokumentation von :latest ab und empfiehlt einen sprechenden Tag wie v1.42.0 oder einen Digest. Ein Digest ist ein Hash über den Inhalt und ändert sich nie, ein Tag kann später auf ein anderes Image zeigen.
Private Registry ohne imagePullSecrets
Für eine private Registry braucht der kubelet Zugangsdaten. Die Dokumentation empfiehlt ein Secret vom Typ kubernetes.io/dockerconfigjson, das du im Pod als imagePullSecrets einträgst:
kubectl create secret docker-registry regcred -n shop \
--docker-server=registry.example.com \
--docker-username=<benutzer> \
--docker-password=<token>
spec:
imagePullSecrets:
- name: regcred
containers:
- name: api
image: registry.example.com/shop/api:1.4.2
Das Secret muss im selben Namespace liegen wie der Pod. Zeigen die Events den Grund FailedToRetrieveImagePullSecret, findet Kubernetes kein Secret mit diesem Namen. Zugangsdaten auf der Kommandozeile landen laut Dokumentation womöglich in deiner Shell-Historie. Leg das Secret deshalb lieber aus einer Datei an (kubectl create secret generic regcred --from-file=.dockerconfigjson=<pfad> --type=kubernetes.io/dockerconfigjson, so beschrieben auf derselben Doku-Seite), und nimm statt deines Passworts ein Token mit reinen Leserechten. Nutzen alle Pods eines Namespace dieselbe Registry, hängst du das Secret an den ServiceAccount der Pods, meist default. Neue Pods mit diesem ServiceAccount bekommen es automatisch, bestehende nicht. Mehr in ConfigMap und Secret in Kubernetes.
Pull-Limit von Docker Hub
Laut Docker-Dokumentation (Stand 28.10.2026) erlaubt Docker Hub nicht angemeldeten Nutzern 100 Pulls in 6 Stunden je IPv4-Adresse oder IPv6-/64-Subnetz, angemeldeten Nutzern mit Personal-Konto 200. Die bezahlten Pläne haben kein Pull-Limit, aber eine Fair-Use-Regel. Alle Nodes, die ohne Anmeldung über dieselbe öffentliche IPv4-Adresse ziehen, teilen sich also ein Kontingent, und ein Image mit mehreren Architekturen zählt als ein Pull je gezogener Architektur.
Ist das Limit erreicht, antwortet Docker Hub mit Statuscode 429 und „You have reached your pull rate limit“. Den Stand zeigen die Header ratelimit-limit und ratelimit-remaining einer HEAD-Anfrage, die laut Docker nicht als Pull zählt. Abhilfe: angemeldet ziehen mit einem imagePullSecret für https://index.docker.io/v1/, ein eigener Mirror, und feste Tags mit imagePullPolicy: IfNotPresent.
Netzwerk, DNS und Proxy
Erreicht der Node die Registry nicht, nennt die Fehlermeldung meist Host und Netzwerkfehler. Typisch sind eine Firewall, ein Proxy, den die Container-Laufzeit nicht kennt, oder ein Name, den der DNS-Server des Nodes nicht auflöst. In meinen Schulungen passiert das auf Firmenrechnern oft: Der Cluster startet, die Pods bleiben in ImagePullBackOff, und fast immer steckt ein Proxy oder eine Firewall dahinter, die den Download der Images blockiert. Wie du das lokal angehst, steht in Kubernetes lokal: Cluster auf dem Rechner. Prüf zuerst vom Node aus, dann im Cluster.
Falsche Prozessorarchitektur
Eine Registry kann laut Kubernetes-Dokumentation einen Image-Index mit einem Image je Architektur ausliefern. Fehlt die Architektur des Nodes, etwa linux/arm64 auf einem Raspberry Pi, bricht containerd mit „no match for platform in manifest“ ab. Welche Plattformen ein Image hat, zeigt docker buildx imagetools inspect <image>. Ist ein Image dagegen falsch gekennzeichnet, lädt der Node es, der Container beendet sich aber sofort, und du landest im CrashLoopBackOff. Mehr in Kubernetes auf dem Raspberry Pi.
Zertifikat der Registry
Nutzt deine Registry ein Zertifikat einer internen Zertifizierungsstelle, scheitert der Pull am TLS-Handshake. Die Zertifizierungsstelle gehört auf jeden Node: bei containerd als Feld ca in einer hosts.toml unter /etc/containerd/certs.d/<registry-host>/, was nur greift, wenn in der containerd-Konfiguration config_path = "/etc/containerd/certs.d" gesetzt ist, in k3s als ca_file unter tls in /etc/rancher/k3s/registries.yaml, danach laut Dokumentation k3s auf jedem Node neu starten. Die Prüfung abzuschalten (insecure_skip_verify bzw. skip_verify) ist höchstens ein kurzer Test.
Nach dem Fix: warten oder neu starten?
Nach dem Fix versucht es der kubelet von selbst wieder, im ungünstigsten Fall erst nach 5 Minuten. Im Quellcode hängt die Wartezeit am einzelnen Pod und Image, ein neuer Pod beginnt ohne Wartezeit. Lag der Fehler außerhalb des Manifests (Image nachgepusht, Secret angelegt, Netzwerk repariert), lösch den Pod, wenn ein Deployment ihn neu anlegt, oder starte das Deployment mit kubectl rollout restart deployment api -n shop neu. Hast du das Manifest geändert, rollt Kubernetes ohnehin neue Pods aus. Wie Rollouts ablaufen, steht in Rolling Update und Rollback in Kubernetes.
So vermeidest du ImagePullBackOff
Vier Gewohnheiten verhindern die meisten Fälle:
- Feste Tags oder Digests statt
:latest, damit Nodes nicht ohne Grund neu ziehen.
- Zugangsdaten am ServiceAccount, damit niemand das
imagePullSecret im Manifest vergisst.
- Eigene Registry oder Mirror für Basis-Images, unabhängig vom Pull-Limit von Docker Hub.
- Builds für alle Architekturen deiner Nodes und eine Prüfung in der Pipeline, dass das Image mit genau diesem Tag existiert. Wie so eine Pipeline aussieht, steht in CI/CD für Kubernetes: die Pipeline.
Häufige Fragen
Was bedeutet ImagePullBackOff?
Der kubelet konnte das Image nicht aus der Registry ziehen und wartet vor dem nächsten Versuch, mit wachsender Pause bis höchstens 5 Minuten. Der Container läuft nicht, der Pod bleibt Pending.
Was ist der Unterschied zwischen ErrImagePull und ImagePullBackOff?
ErrImagePull meldet einen gescheiterten Versuch, ImagePullBackOff die Wartezeit danach. Die Ursache ist dieselbe und steht in den Events von kubectl describe pod.
Wie behebe ich ImagePullBackOff bei einer privaten Registry?
Leg mit kubectl create secret docker-registry ein Secret im Namespace des Pods an und trag es unter imagePullSecrets ein. Bei FailedToRetrieveImagePullSecret stimmt der Name oder der Namespace nicht.
Warum funktioniert docker pull bei mir, aber nicht im Cluster?
Weil dein Rechner und der Node verschiedene Zugangsdaten, Netzwerke und Zertifikate haben, oft auch eine andere Architektur. Teste deshalb auf dem Node selbst, zum Beispiel mit crictl pull und bei privater Registry mit --creds.
Wie du weitermachst
ImagePullBackOff tritt vor dem Start des Containers auf. Läuft das Image, stürzt der Container aber ab, hilft CrashLoopBackOff: Pods richtig debuggen. Beendet der Kernel ihn wegen Speichermangels, lies Kubernetes OOMKilled: erkennen und beheben.
Mein Vorschlag für den nächsten Fall: kubectl describe pod, den Text nach „Failed to pull image“ lesen, die Ursache in der Tabelle oben suchen. Die Grundlagen zu Pods und zur Kommandozeile stehen in meinem Kubernetes-Praxisbuch bei Rheinwerk.