← Terug naar tutorials

ImagePullBackOff-achtige failures oplossen in Docker-only productieomgevingen

dockerdevopscontainer-registriesimage-pulltroubleshootingproductionregistry-authtls-certificatendnsrate-limits

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

  1. Wat is het Docker-equivalent van ImagePullBackOff?
  2. Snelle triage: wat faalt er precies?
  3. Veelvoorkomende foutcategorieën en oplossingen
  4. Diepe debugging met logs en tracing
  5. Structurele mitigaties voor productie
  6. Praktische runbook: stap-voor-stap checklist

Wat is het Docker-equivalent van ImagePullBackOff?

In Docker-only omgevingen zie je pull-problemen terug als:

Typische meldingen:

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:

  1. Welke host(s) falen?
  2. Welke image (naam + tag/digest)?
  3. Welke registry (Docker Hub, GHCR, ECR, GCR, Harbor, Nexus, Artifactory, eigen registry)?
  4. Is het een nieuw probleem (na deploy) of bestaand (na reboot)?
  5. 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

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

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

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:

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

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

Diagnose Herken de fout in output van docker pull of Compose.

Oplossingen

  1. Log in op Docker Hub (verhoogt limieten afhankelijk van account).
  2. Gebruik een mirror/cache (bijv. Harbor/Nexus/Artifactory als pull-through cache).
  3. Pin images en pre-pull tijdens maintenance windows.
  4. 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

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

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

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

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

Image verkleinen (preventief)


7) Disk space, inode-uitputting en corruptie

Symptomen

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

docker system prune -af
docker volume prune -f

Wees voorzichtig: -a verwijdert ook ongebruikte images die je misschien als cache nodig hebt.

Corruptie Soms raakt de local layer store inconsistent na harde reboot of disk issues.


8) Docker daemon/config problemen

Symptomen

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

Oplossing

sudo systemctl restart docker
docker pull hello-world
docker run --rm hello-world

9) Platform mismatch (amd64/arm64) en manifest issues

Symptomen

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

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

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


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):

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:


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:

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:

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:

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:

Pragmatisch:

5) Hardening van credentials


Praktische runbook: stap-voor-stap checklist

Gebruik deze checklist tijdens een incident om snel van symptoom naar oorzaak te gaan.

Stap 0 — Verzamel feiten

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

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:

Stap 8 — Kijk in daemon logs voor de echte oorzaak

sudo journalctl -u docker -n 400 --no-pager

Zoek naar:


Veelvoorkomende scenario’s (met snelle fixes)

Scenario A: manifest unknown na deploy

Oorzaak: tag bestaat niet (typo) of is nog niet gepusht.

Fix

Scenario B: unauthorized op één host maar niet op andere

Oorzaak: credentials ontbreken of verlopen op die host, of andere user-context.

Fix

Scenario C: x509 unknown authority naar interne registry

Oorzaak: interne CA niet geïnstalleerd.

Fix

Scenario D: Pull hangt bij grote layers

Oorzaak: netwerk/MTU/proxy issues of registry performance.

Fix


Afsluiting

ImagePullBackOff-achtige failures in Docker-only productieomgevingen zijn bijna altijd terug te brengen tot één van deze assen:

  1. Naam/tag/digest klopt niet
  2. Auth (token/permissions) klopt niet
  3. Netwerk (DNS/TLS/proxy/egress) faalt
  4. Registry limieten of performance
  5. Host resources (disk/inodes) of daemon issues
  6. 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.