- Not logged in against the target registry.
- Namespace/repo path doesn't match an account you can push to.
- Token expired (CI runners: refresh registry credentials).
diagnose
docker login ghcr.io -u <user>
cat ~/.docker/config.json | jq '.auths | keys'
push again
docker push registry.example.com/team/app:tag
- Tag typo, image never pushed, or repo is private.
- Docker Hub rate limit returns similar errors anonymously.
diagnose
docker manifest inspect image:tag
curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:library/nginx:pull" | jq -r .token | head -c 40; echo
- CMD/ENTRYPOINT binary missing or wrong path.
- App crashed at boot — read logs first.
- PID 1 signal handling kills the container early.
diagnose
docker logs --tail=100 <name>
docker inspect <name> --format '{{.State.ExitCode}} {{.State.Error}}'
docker run --rm -it --entrypoint sh image:tag # poke around interactively
- App bound to 127.0.0.1 inside the container instead of 0.0.0.0.
- -p order reversed: it's host:container.
- Host firewall / security group blocks the port.
diagnose
docker port <name>
curl -v localhost:<host-port>/healthz
docker exec <name> netstat -tlnp 2>/dev/null || docker exec <name> ss -tlnp
- Dangling images and stopped containers pile up fast on CI machines.
- Build cache grows unbounded without pruning strategy.
reclaim space
docker system df # see usage breakdown first
docker system prune -af --volumes # careful: removes unused volumes too
docker builder prune -af # build cache only
- COPY . before dependency install invalidates layers on every change.
- Order matters: deps first, source last.
- Use BuildKit cache mounts for package managers.
pattern
COPY package*.json ./\nRUN npm ci\nCOPY . .\nRUN npm run build
cache mount (buildkit)
RUN --mount=type=cache,target=/root/.npm npm ci