ImagePullBackOff-achtige failures oplossen in Docker-only productieomgevingen
In Kubernetes zie je vaak de fout ImagePullBackOff wanneer een node een containerimage niet kan ophalen. In een Docker-only productieomgeving (dus zonder Kubernetes) bestaat die specifieke status niet, maar je krijgt functioneel dezelfde klasse problemen: containers starten niet, services blijven “down”, deployments falen, of docker run/docker compose up eindigt met pull-fouten, timeouts of auth-errors.
Deze tutorial is een diepgaande handleiding om ImagePullBackOff-achtige failures in Docker-only omgevingen systematisch te diagnosticeren en op te lossen. Je krijgt concrete commando’s, herkenbare symptomen, oorzaken, en structurele mitigaties (zodat het probleem niet terugkomt).
Inhoud
- Wat is het Docker-equivalent van ImagePullBackOff?
- Snelle triage: wat faalt er precies?
- Veelvoorkomende foutcategorieën en oplossingen
- 1) Verkeerde image-naam of tag
- 2) Authenticatie/authorisatie (private registry)
- 3) Rate limiting (Docker Hub) en throttling
- 4) Netwerk/DNS/TLS issues
- 5) Proxy’s en corporate netwerken
- 6) Registry onbereikbaar of traag
- 7) Disk space, inode-uitputting en corruptie
- 8) Docker daemon/config problemen
- 9) Platform mismatch (amd64/arm64) en manifest issues
- 10) Content trust, signatures en policy
- Diepe debugging met logs en tracing
- Structurele mitigaties voor productie
- Praktische runbook: stap-voor-stap checklist
Wat is het Docker-equivalent van ImagePullBackOff?
In Docker-only omgevingen zie je pull-problemen terug als:
docker pullfaalt (metunauthorized,not found,TLS handshake timeout, etc.)docker runfaalt omdat de image niet lokaal aanwezig is en pull misluktdocker compose upstopt of blijft hangen bijPulling ...en eindigt met errors- systemd-services die
docker run ...uitvoeren blijven crashen/restarten
Typische meldingen:
Error response from daemon: pull access denied for ...manifest for repo:tag not found: manifest unknownnet/http: TLS handshake timeoutx509: certificate signed by unknown authoritytoomanyrequests: You have reached your pull rate limitno matching manifest for linux/arm64/v8 in the manifest list entries
Belangrijk: Docker heeft geen “BackOff status” zoals Kubernetes, maar je orchestrationlaag (systemd, Compose, eigen scripts, CI/CD) kan wél retries doen. Daardoor zie je vaak herhaalde failures die lijken op backoff.
Snelle triage: wat faalt er precies?
Begin met het scherp krijgen van:
- Welke host(s) falen?
- Welke image (naam + tag/digest)?
- Welke registry (Docker Hub, GHCR, ECR, GCR, Harbor, Nexus, Artifactory, eigen registry)?
- Is het een nieuw probleem (na deploy) of bestaand (na reboot)?
- Faalt pull overal of alleen op sommige nodes?
Basiscommando’s
Controleer Docker status:
sudo systemctl status docker --no-pager
docker version
docker info
Test een pull expliciet (met duidelijke output):
docker pull --quiet=false nginx:1.27
Als je Compose gebruikt:
docker compose version
docker compose pull --no-parallel
docker compose up -d
docker compose logs -n 200
Bekijk welke images lokaal aanwezig zijn:
docker images --digests
docker image ls
Controleer of de image misschien al lokaal bestaat maar de tag anders is:
docker image inspect myrepo/myapp:prod --format '{{json .RepoDigests}}'
Veelvoorkomende foutcategorieën en oplossingen
1) Verkeerde image-naam of tag
Symptomen
manifest unknownnot foundpull access denied(soms misleidend; kan ook door typo komen)
Diagnose Controleer exact wat je probeert te pull-en:
docker pull myrepo/myapp:prodd
Als dat faalt, kijk of de tag bestaat (afhankelijk van registry). Voor Docker Hub kun je via web of API kijken; voor veel private registries heb je een catalog API.
Voor een Docker Registry v2 (als het toegestaan is) kun je:
curl -sSL https://REGISTRY.DOMAIN/v2/_catalog | jq .
En tags:
curl -sSL https://REGISTRY.DOMAIN/v2/myrepo/myapp/tags/list | jq .
Oplossing
- Fix de tag/naam in je deployment/Compose/systemd unit.
- Gebruik bij voorkeur immutable references: pull op digest in plaats van tag.
Voorbeeld: pin op digest:
docker pull myrepo/myapp@sha256:0123456789abcdef...
docker run myrepo/myapp@sha256:0123456789abcdef...
Voordeel: je weet zeker dat je overal exact dezelfde image draait.
2) Authenticatie/authorisatie (private registry)
Symptomen
unauthorized: authentication requireddenied: requested access to the resource is deniedpull access denied
Diagnose Test login:
docker login REGISTRY.DOMAIN
Of met username/password (bij CI liever tokens):
echo "$REGISTRY_PASSWORD" | docker login REGISTRY.DOMAIN -u "$REGISTRY_USER" --password-stdin
Controleer welke credentials Docker gebruikt:
- Docker bewaart credentials in
~/.docker/config.json(of root’s home als je met sudo werkt). - In productie kan dit misgaan als je scripts als root draaien maar je als user hebt ingelogd (of andersom).
Bekijk config:
sudo cat /root/.docker/config.json
cat ~/.docker/config.json
Veelgemaakte fout: “ik ben ingelogd” maar de service draait als andere user
Bijvoorbeeld: je test als deploy user, maar systemd unit gebruikt User=app of draait als root.
Oplossing
- Zorg dat de juiste user ingelogd is, of configureer een credential helper.
- Gebruik tokens met minimale rechten.
- Voor systemd: maak expliciet welke user de pull doet, of voer
docker loginuit in de juiste context.
Voorbeeld: login als root (alleen als je daemon als root gebruikt):
sudo -i
docker login REGISTRY.DOMAIN
Extra: AWS ECR Voor ECR is login tijdelijk:
aws ecr get-login-password --region eu-west-1 \
| docker login --username AWS --password-stdin 123456789012.dkr.ecr.eu-west-1.amazonaws.com
Plan dit in je deploy (en herhaal regelmatig).
3) Rate limiting (Docker Hub) en throttling
Symptomen
toomanyrequests: You have reached your pull rate limit- Pulls werken soms wel, soms niet (spikes bij deploy)
Diagnose
Herken de fout in output van docker pull of Compose.
Oplossingen
- Log in op Docker Hub (verhoogt limieten afhankelijk van account).
- Gebruik een mirror/cache (bijv. Harbor/Nexus/Artifactory als pull-through cache).
- Pin images en pre-pull tijdens maintenance windows.
- Verminder parallel pulls.
Compose pull zonder parallel:
docker compose pull --no-parallel
Pre-pull op hosts:
docker pull nginx:1.27
docker pull redis:7.4
Structureel: zet een interne registry-cache op en laat hosts daarvandaan pullen.
4) Netwerk/DNS/TLS issues
Symptomen
TLS handshake timeouti/o timeoutdial tcp: lookup registry-1.docker.io: no such hostx509: certificate signed by unknown authority
Diagnose: DNS Test DNS-resolutie:
getent hosts registry-1.docker.io
getent hosts REGISTRY.DOMAIN
Test met dig (indien beschikbaar):
dig +short registry-1.docker.io
Diagnose: connectiviteit Test TCP/HTTPS:
curl -v https://registry-1.docker.io/v2/ 2>&1 | tail -n 50
curl -v https://REGISTRY.DOMAIN/v2/ 2>&1 | tail -n 50
Let op: veel registries geven 401 Unauthorized op /v2/ — dat is goed: het betekent dat TLS en routing werken.
Diagnose: certificaten
Als je x509 ziet bij een private registry met eigen CA, dan vertrouwt de host die CA niet.
Check certificaatketen:
echo | openssl s_client -connect REGISTRY.DOMAIN:443 -servername REGISTRY.DOMAIN 2>/dev/null | openssl x509 -noout -issuer -subject -dates
Oplossingen
- Fix DNS (systemd-resolved, resolv.conf, upstream resolvers).
- Sta outbound 443 toe naar registry endpoints.
- Installeer interne CA op de host en herstart Docker.
Voor Debian/Ubuntu (CA toevoegen):
sudo cp my-ca.crt /usr/local/share/ca-certificates/my-ca.crt
sudo update-ca-certificates
sudo systemctl restart docker
Voor RHEL/CentOS:
sudo cp my-ca.crt /etc/pki/ca-trust/source/anchors/
sudo update-ca-trust
sudo systemctl restart docker
5) Proxy’s en corporate netwerken
Symptomen
- Pull werkt op sommige netwerken wel, op productie niet
- Timeouts of TLS errors
proxyconnect tcp: ...
Diagnose Check of Docker daemon proxy settings heeft:
systemctl show docker --property=Environment
Check drop-in config:
sudo systemctl cat docker
Zoek naar HTTP_PROXY, HTTPS_PROXY, NO_PROXY.
Oplossing: proxy correct instellen voor Docker daemon Maak een systemd drop-in:
sudo mkdir -p /etc/systemd/system/docker.service.d
sudo tee /etc/systemd/system/docker.service.d/proxy.conf >/dev/null <<'EOF'
[Service]
Environment="HTTP_PROXY=http://proxy.company:3128"
Environment="HTTPS_PROXY=http://proxy.company:3128"
Environment="NO_PROXY=localhost,127.0.0.1,::1,REGISTRY.DOMAIN,10.0.0.0/8,192.168.0.0/16"
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
Test opnieuw:
docker pull alpine:3.20
Let op: NO_PROXY is cruciaal voor interne registries; anders gaat verkeer onnodig via de proxy en faalt mTLS/hostname checks.
6) Registry onbereikbaar of traag
Symptomen
context deadline exceeded- Pull duurt extreem lang
- Alleen grote layers falen
Diagnose Meet latency en throughput:
curl -o /dev/null -s -w 'time_total=%{time_total} connect=%{time_connect} starttransfer=%{time_starttransfer}\n' \
https://REGISTRY.DOMAIN/v2/
Als je een registry beheert: check server logs en storage backend.
Oplossingen
- Zet registry dichter bij de hosts (region/zone).
- Gebruik caching registry of replicatie.
- Verhoog timeouts (soms nodig bij hele grote images) — maar liever images verkleinen.
Image verkleinen (preventief)
- Multi-stage builds
- Minder layers
- Geen build tools in runtime image
- Gebruik
alpineof distroless waar passend
7) Disk space, inode-uitputting en corruptie
Symptomen
- Pull faalt met “no space left on device”
- Docker kan layers niet uitpakken
- Onverwachte errors tijdens extract
Diagnose Check disk:
df -h
df -i
Check Docker disk usage:
docker system df
docker system df -v
Check Docker root dir:
docker info | grep -i "Docker Root Dir"
sudo du -sh /var/lib/docker
Oplossingen
- Ruim ongebruikte images/containers/networks op:
docker system prune -af
docker volume prune -f
Wees voorzichtig: -a verwijdert ook ongebruikte images die je misschien als cache nodig hebt.
- Verplaats Docker data root naar grotere disk (gepland change).
- Monitor disk/inodes structureel (Prometheus node_exporter, etc.).
Corruptie Soms raakt de local layer store inconsistent na harde reboot of disk issues.
- Check daemon logs (zie sectie “Diepe debugging”).
- In extreme gevallen: stop Docker en herstel
/var/lib/dockervanuit backup of rebuild host.
8) Docker daemon/config problemen
Symptomen
- Pull faalt op daemon-niveau, niet per se netwerk
Error response from daemon: ...- Docker reageert traag of niet
Diagnose Bekijk daemon logs:
sudo journalctl -u docker -n 300 --no-pager
Check storage driver:
docker info | grep -i "Storage Driver"
Controleer /etc/docker/daemon.json:
sudo cat /etc/docker/daemon.json
Veelvoorkomende config-issues
- Verkeerde
registry-mirrors insecure-registriesverkeerd ingesteld- DNS settings in daemon die niet kloppen
Oplossing
- Fix config, herstart Docker:
sudo systemctl restart docker
- Test met een simpele image:
docker pull hello-world
docker run --rm hello-world
9) Platform mismatch (amd64/arm64) en manifest issues
Symptomen
no matching manifest for linux/arm64/v8 in the manifest list entries- Image werkt op x86 servers, faalt op ARM (of andersom)
Diagnose Check host architecture:
uname -m
docker info | grep -i "Architecture"
Inspecteer manifest (Docker 20.10+):
docker manifest inspect myrepo/myapp:1.2.3 | head -n 50
Oplossingen
- Bouw en push multi-arch images (buildx).
- Of forceer platform bij pull/run (alleen als je emulatie hebt met qemu, meestal niet ideaal in productie):
docker pull --platform=linux/amd64 myrepo/myapp:1.2.3
Buildx voorbeeld (CI) Op een build machine:
docker buildx create --use
docker buildx build --platform linux/amd64,linux/arm64 \
-t myrepo/myapp:1.2.3 \
-t myrepo/myapp:latest \
--push .
10) Content trust, signatures en policy
Sommige omgevingen gebruiken Docker Content Trust (Notary v1) of registry policies die unsigned images blokkeren.
Symptomen
- Pull faalt alleen in productie met policy enforcement
- Errors rond trust data / signatures
Diagnose Check of content trust aan staat:
echo "$DOCKER_CONTENT_TRUST"
Test met uitgeschakeld (alleen als policy dit toelaat):
DOCKER_CONTENT_TRUST=0 docker pull myrepo/myapp:1.2.3
Oplossing
- Sign images in je pipeline volgens je policy.
- Documenteer welke keys en rotatieprocedures gelden.
- Gebruik digests en attestation (afhankelijk van tooling: cosign/sigstore) als je stack dat ondersteunt.
Diepe debugging met logs en tracing
Wanneer de standaard foutmelding niet genoeg is, ga je dieper.
Docker daemon logs
sudo journalctl -u docker --since "1 hour ago" --no-pager
sudo journalctl -u docker -f
Zoek op termen als error, pull, x509, timeout, registry.
Compose events en container lifecycle
Compose toont vaak pull-stappen. Gebruik:
docker compose up
en in een tweede terminal:
docker events --since 10m
Je ziet dan events zoals pull, create, start, die.
Netwerk tracing (basis)
Check routes:
ip route
Check of je überhaupt naar buiten kunt:
curl -I https://1.1.1.1
curl -I https://google.com
Check MTU issues (soms bij VPN/overlay):
- Symptoom: kleine requests werken, grote layer downloads hangen.
- Diagnose: ping met “do not fragment” (werkt niet overal, maar nuttig):
ping -M do -s 1472 8.8.8.8
Als dit faalt, kan je MTU te groot zijn voor het pad.
TLS debugging
Soms is SNI/hostname mismatch of intercepting proxy de boosdoener.
openssl s_client -connect REGISTRY.DOMAIN:443 -servername REGISTRY.DOMAIN -showcerts </dev/null
Let op:
- Issuer/Subject klopt?
- Expiry?
- Zit er een corporate intercept-CA tussen?
Structurele mitigaties voor productie
Incidenten oplossen is één ding; voorkomen is beter. Hieronder maatregelen die in Docker-only productieomgevingen veel ellende schelen.
1) Gebruik een interne registry of pull-through cache
Voordelen:
- Minder afhankelijk van Docker Hub rate limits
- Snellere pulls (lokaal netwerk)
- Betere controle (retentie, auditing)
Tools: Harbor, Nexus Repository, Artifactory, Docker Registry v2.
Als je een mirror gebruikt, configureer daemon.json:
sudo tee /etc/docker/daemon.json >/dev/null <<'EOF'
{
"registry-mirrors": ["https://mirror.registry.local"],
"log-driver": "json-file",
"log-opts": { "max-size": "50m", "max-file": "3" }
}
EOF
sudo systemctl restart docker
Test:
docker pull alpine:3.20
2) Pin op digests en voer controlled rollouts uit
Tags zoals latest zijn riskant: dezelfde tag kan andere bits betekenen op verschillende momenten.
Aanpak:
- CI bouwt image, pushed tag + digest
- Deployment gebruikt digest
- Rollback = terug naar vorige digest
Voorbeeld:
docker pull myrepo/myapp@sha256:...
docker tag myrepo/myapp@sha256:... myrepo/myapp:prod
3) Pre-pull en warm-up bij deploy
Zeker bij meerdere hosts:
- Pull eerst images op alle hosts
- Start daarna containers
Voorbeeld (simpel, handmatig):
for host in app1 app2 app3; do
ssh "$host" "docker pull myrepo/myapp:1.2.3"
done
for host in app1 app2 app3; do
ssh "$host" "docker stop myapp || true && docker rm myapp || true && docker run -d --name myapp myrepo/myapp:1.2.3"
done
4) Observability: monitor pulls, disk, en daemon health
Minimaal:
- Disk usage en inode usage
- Docker daemon up/down
- Network egress errors
- Registry latency/availability
Pragmatisch:
- Alert op
df -h> 80% - Alert op
systemctl is-active docker!= active - Log scraping van
journalctl -u dockervoorx509,timeout,toomanyrequests
5) Hardening van credentials
- Gebruik short-lived tokens waar mogelijk (ECR/GCR)
- Beperk scope (read-only voor pull hosts)
- Rotatieproces + noodprocedure
- Vermijd plaintext secrets in scripts; gebruik
--password-stdin
Praktische runbook: stap-voor-stap checklist
Gebruik deze checklist tijdens een incident om snel van symptoom naar oorzaak te gaan.
Stap 0 — Verzamel feiten
- Welke host(s)?
- Welke image reference (incl. tag/digest)?
- Welke registry?
- Sinds wanneer?
Stap 1 — Reproduceer met docker pull
docker pull myrepo/myapp:1.2.3
Lees de exacte fouttekst.
Stap 2 — Check basis: daemon en disk
sudo systemctl status docker --no-pager
df -h
df -i
docker system df
Als disk/inodes vol: prune of uitbreiden.
Stap 3 — Check auth
Voor private registry:
docker logout REGISTRY.DOMAIN
docker login REGISTRY.DOMAIN
docker pull myrepo/myapp:1.2.3
Let op user-context (root vs non-root).
Stap 4 — Check DNS en TLS
getent hosts REGISTRY.DOMAIN
curl -v https://REGISTRY.DOMAIN/v2/ 2>&1 | tail -n 60
401is OK.- TLS errors: CA installeren of intercepting proxy fixen.
Stap 5 — Check proxy settings (indien relevant)
systemctl show docker --property=Environment
sudo systemctl cat docker
Corrigeer NO_PROXY voor interne registries.
Stap 6 — Check platform mismatch
uname -m
docker manifest inspect myrepo/myapp:1.2.3 | head
Bouw multi-arch of gebruik juiste tag.
Stap 7 — Check rate limiting
Als je toomanyrequests ziet:
- login op Docker Hub
- mirror/cache
- minder parallel pulls
Stap 8 — Kijk in daemon logs voor de echte oorzaak
sudo journalctl -u docker -n 400 --no-pager
Zoek naar:
- storage driver errors
- TLS/cert errors
- timeouts
- permission issues
Veelvoorkomende scenario’s (met snelle fixes)
Scenario A: manifest unknown na deploy
Oorzaak: tag bestaat niet (typo) of is nog niet gepusht.
Fix
- Controleer CI push stap
- Gebruik digest
- Voeg “promote” stap toe: pas deploy aan nadat push succesvol is
Scenario B: unauthorized op één host maar niet op andere
Oorzaak: credentials ontbreken of verlopen op die host, of andere user-context.
Fix
docker loginop die host als juiste user- Automatiseer login (ECR token refresh)
- Centraliseer pulls via registry mirror
Scenario C: x509 unknown authority naar interne registry
Oorzaak: interne CA niet geïnstalleerd.
Fix
- CA toevoegen aan OS trust store
- Docker herstarten
- Verifieer met
curl -v https://REGISTRY.DOMAIN/v2/
Scenario D: Pull hangt bij grote layers
Oorzaak: netwerk/MTU/proxy issues of registry performance.
Fix
- Test zonder proxy (tijdelijk) of fix proxy
- MTU check
- Image verkleinen
- Registry dichterbij / caching
Afsluiting
ImagePullBackOff-achtige failures in Docker-only productieomgevingen zijn bijna altijd terug te brengen tot één van deze assen:
- Naam/tag/digest klopt niet
- Auth (token/permissions) klopt niet
- Netwerk (DNS/TLS/proxy/egress) faalt
- Registry limieten of performance
- Host resources (disk/inodes) of daemon issues
- Platform mismatch
De sleutel is om niet te gokken, maar een vaste volgorde aan te houden: reproduceer met docker pull, controleer daemon/disk, valideer auth, test /v2/ met curl, inspecteer logs, en pas structurele mitigaties toe (mirror/cache, digests, pre-pull, monitoring).
Als je wilt, kan ik je omgeving-specifiek helpen door één foutmelding (exacte output van docker pull ...), je OS/distributie, en je registry-type te analyseren en daar een gericht runbook van te maken.