skip to content

Registries & Distribution

Moving an image between a build and a runtime: the push and pull exchange, credentials in ~/.docker/config.json, tag versus digest addressing, and signing. Asked because every deploy starts with a pull that must be authenticated, fast and reproducible.

part ofDockeroverview, primer and where to startread it →
on this pageshow

questions

page 1 of 2

A `docker pull` of an image from your company's internal registry fails with `pull access denied for myapp, repository does not exist or may require 'docker login'`. What does that error actually mean, and how do you work through it?

level: juniorimportance: must knowfreq 58%

answer

  1. 401 not 404 — existence hidden on purpose
  2. No host in reference → docker.io/library
  3. Login is per registry host
  4. ECR token expires in 12 h
  5. manifest unknown = auth was fine

basics

~20 s

The registry answered with an auth error, and the client cannot tell "no such repository" from "you are not allowed". Check the image reference includes the registry hostname, run docker login <registry> with valid credentials, and confirm your account has pull rights on that repository.

solid answer

~50 s

That message is Docker's catch-all for an unauthenticated or unauthorized response on the manifest request. Registries deliberately return 401 rather than 404 for repositories you cannot see, so "does not exist" and "no permission" collapse into one message. I work through it in order: 1. **Check the reference.** `docker pull myapp:1.2` with no host resolves to `docker.io/library/myapp` — a public Hub repo, not our registry. It must be `registry.corp.example.com/team/myapp:1.2`. 2. **Check I am logged in to *that* host.** `docker login registry.corp.example.com`; credentials are per-registry-host, so being logged in to Hub does nothing here. 3. **Check the credential is still valid.** Cloud registry tokens expire (ECR's is 12 hours); a stale entry in `~/.docker/config.json` gives the same error. 4. **Check permissions on the exact repository path.** Access is usually scoped per repository or project, so I may be able to pull `team/other` and not `team/myapp`. 5. **Check *where* it fails** — a CI runner or a server has its own credential store; my laptop working proves nothing.

code

bash · 15 lines
bash
# Wrong: resolves to docker.io/library/myapp
docker pull myapp:1.2

# Right: explicit registry host
docker pull registry.corp.example.com/team/myapp:1.2

# Authenticate against that specific host
docker login registry.corp.example.com -u ci-bot --password-stdin < token.txt

# Which hosts do I currently hold credentials for?
cat ~/.docker/config.json

# Amazon ECR: password is a short-lived token, username is literally 'AWS'
aws ecr get-login-password --region eu-west-1 \
  | docker login --username AWS --password-stdin 111122223333.dkr.ecr.eu-west-1.amazonaws.com

go deeper

for a junior

Know the message means an auth failure, that references without a hostname go to Docker Hub, and that docker login <registry> is the first fix.

for a middle

Explain why registries return 401 rather than 404, that credentials are keyed per host, and that cloud tokens expire.

for a senior

Separate authentication from authorization quickly, reason about where the pull actually runs (runner, node, user), and point at repository-scoped grants.

for a principal

Frame it as an identity and credential-distribution problem: which identities exist, how they are minted and rotated, and why humans and machines should not share them.

## What the error really is When you run `docker pull`, the daemon asks the registry for the image manifest: `GET /v2/<repository>/manifests/<tag>`. If the registry answers `401 Unauthorized` (or `403 Forbidden`) instead of the manifest, the CLI prints `pull access denied for <name>, repository does not exist or may require 'docker login'`. The wording is vague on purpose. A registry that returned `404 Not Found` for private repositories would leak which repositories exist to anyone who probes it. So most registries — Docker Hub included — answer *unauthenticated* requests for both "missing" and "private but real" repositories the same way. The client cannot distinguish them, so it prints both possibilities. ## The image reference is the first suspect A Docker image reference has the shape `[registry-host[:port]/]namespace/name[:tag|@digest]`. When the first path component contains no dot or colon and is not `localhost`, Docker does **not** treat it as a hostname — it defaults the registry to Docker Hub (`docker.io`) and, if there is no namespace, prefixes `library/`. - `myapp:1.2` → `docker.io/library/myapp:1.2` - `team/myapp:1.2` → `docker.io/team/myapp:1.2` - `registry.corp.example.com/team/myapp:1.2` → your registry (the dot makes it a host) So the single most common cause of this error is a reference that silently points at Docker Hub, where the repository genuinely does not exist. ## Credentials are per registry host `docker login` takes a registry host and stores an entry keyed by that host. `docker login` with no argument targets Docker Hub. Being authenticated to Hub grants nothing on `registry.corp.example.com`, and vice versa. `docker logout <host>` removes the entry. Some registries also require a specific username convention or a token rather than your interactive password: Docker Hub wants a personal access token when 2FA is on, GitHub Container Registry wants a PAT with `read:packages`, and Amazon ECR wants the literal username `AWS` with a short-lived password produced by `aws ecr get-login-password`. ## Expiry Cloud registry credentials are usually time-limited. An ECR authorization token lasts 12 hours; after that, the stored entry is still present in the config file but rejected by the registry, producing exactly the same denial message. "It worked this morning" is a strong hint that the credential expired rather than that permissions changed. The durable fix is a credential helper that mints a fresh token on every request rather than a one-off login. ## Permissions are scoped per repository Even when authenticated, authorization is granted per repository (or per project/namespace). Harbor grants roles inside a project; ECR combines IAM policies with repository policies; Artifact Registry uses IAM roles per repository. So `docker pull registry/team-a/svc` can succeed while `registry/team-b/svc` fails for the same user. The error text is identical, which is why checking the exact repository path against the access model matters. ## Where the pull runs matters The credential store belongs to the user account on the machine running the Docker client. Your laptop, a CI runner, and a production host each have their own `~/.docker/config.json`. A pull that works locally and fails in CI almost always means the pipeline never logged in, logged in as a different identity, or ran as a different OS user than the one that holds the config file. Container orchestrators solve this with their own credential objects rather than a shell login — that is orchestrator territory, but the underlying registry auth is the same. ## A practical checklist 1. Print the full reference you are pulling; add the registry host if missing. 2. `docker login <host>` and watch for `Login Succeeded`. 3. Re-pull. If it still fails, you have an authorization (not authentication) problem: ask for pull rights on that specific repository. 4. Confirm the tag exists — a valid repository with a wrong tag gives `manifest unknown`, a *different* error, which is itself useful evidence that auth is fine. 5. Reproduce on the machine that actually failed, as the user that actually runs Docker.

  • The same pull works on your laptop but fails on a CI runner. What do you check?
    The runner has its own credential store under the user that executes the job, so the login step either never ran, ran as a different OS user, or used a different identity. I check that the pipeline performs a registry login before the pull, that the secret it uses is present and non-expired in that environment, and that the login host string matches the image reference exactly. Ephemeral runners lose `~/.docker/config.json` between jobs, so the login must be part of every job.
  • You are logged in successfully but the pull is still denied. What is happening?
    Authentication succeeded, authorization did not: the identity is valid but has no pull permission on that particular repository. Registries scope grants per repository, project, or namespace, so I verify the exact repository path against the access model and request the read grant for it. If the registry issues scoped bearer tokens, the returned token simply lacks the `pull` action for that repository scope.

It is like a building where the receptionist says "no such tenant, or you're not on the list" for every name they won't confirm — the answer is identical whether the office is empty or you simply lack a badge.

saying these in an interview costs you the question

  • Reading "repository does not exist" literally and concluding the image was deleted
  • Believing one `docker login` authenticates you to every registry
  • Pulling `myapp:1.2` and expecting it to hit the company registry
  • Assuming an old successful login stays valid forever on cloud registries
  • Fixing it by adding the registry to `insecure-registries`, which addresses TLS, not authorization

context

open as a page

In `docker pull` output, what do the per-layer lines `Already exists`, `Downloading` and `Extracting` each mean?

level: juniorimportance: must knowfreq 68%

basics

~20 s

Already exists means that layer, identified by its sha256 digest, is already in the host's local image store, so nothing is transferred. Downloading is the compressed layer blob arriving from the registry. Extracting is that blob being decompressed and unpacked onto disk.

open as a page

A `docker pull` from Docker Hub fails with `toomanyrequests: You have reached your pull rate limit`. What is Docker Hub actually counting, how does the limit differ for anonymous versus authenticated pulls, and what is your first fix?

level: juniorimportance: must knowfreq 60%

basics

~20 s

Docker Hub counts image manifest requests, not layers or bytes. Anonymous pulls are counted per source IP address and get the smallest quota; authenticated pulls count against your Docker account and get more; paid plans get more still. First fix: docker login on the machine that pulls.

open as a page

Why does a CI job push one container image under both a git-SHA tag and a `stable` tag?

level: juniorimportance: must knowfreq 72%

basics

~20 s

The git-SHA tag is a permanent name for one exact build, so it can be redeployed later and traced back to a commit. The stable tag only points at whichever build is current, so it answers what is live now, not what shipped when.

open as a page

A team deploys containers using the image tag `:latest`. What problems does that cause, and what would you use instead?

level: juniorimportance: must knowfreq 65%

basics

~20 s

:latest is an ordinary mutable tag with no special meaning — it is not "the newest image". Different hosts can run different content under the same name, rollback has nothing to roll back to, and caching makes it unpredictable. Deploy explicit version tags resolved to digests.

open as a page

In a container registry, what is the difference between referencing an image by tag (for example myapp:1.4) and referencing it by its sha256 digest (myapp@sha256:ab12...)?

level: juniorimportance: must knowfreq 60%

basics

~20 s

A tag is a mutable, human-friendly label the registry can repoint to different content at any time. A sha256 digest is the hash of the image manifest, so it is immutable and content-addressed: the same digest always resolves to exactly the same bytes.

open as a page

In `docker buildx`, how do you attach an SBOM and provenance to an image, and where is that data stored?

level: middleimportance: must knowfreq 55%

basics

~20 s

Pass --sbom=true and --provenance=mode=max to docker buildx build. BuildKit writes each attestation as its own manifest inside the image's OCI index, next to the platform manifests — not as an extra image layer, so layers and config are untouched.

open as a page

Walk through what a container client sends to a registry during an image push: which objects are uploaded, in what order, and why the manifest is written last.

level: middleimportance: must knowfreq 50%

basics

~20 s

For each layer and the config blob, the client HEADs the blob digest; if absent it opens an upload session, sends the bytes, and completes with the digest. Only after every referenced blob exists does it PUT the manifest under the tag — so a tag never resolves to missing content.

open as a page

What does cryptographically signing a container image give you that referencing the image by its `sha256:` digest does not — and what does digest pinning give you that a signature does not?

level: middleimportance: must knowfreq 45%

basics

~20 s

A digest guarantees integrity: you got exactly those bytes, unchanged. It says nothing about who produced them or whether they were approved. A signature adds authenticated provenance: identity X asserts this digest is good. You need both — verify the signature, then deploy by digest.

open as a page

What is the difference between `docker save` / `docker load` and `docker push` / `docker pull`, and when would you reach for the save/load pair?

level: juniorimportance: should knowfreq 44%

basics

~20 s

Push and pull transfer an image to and from a registry over HTTP, uploading only layers the registry lacks. Save writes the whole image — layers, config, tags — into a tar file that load reads back. Use save/load for air-gapped transfer or when no registry is available.

open as a page

What is a Docker credential helper (a `docker-credential-*` binary), and why do cloud registries such as Amazon ECR effectively require one instead of a one-off `docker login`?

level: middleimportance: should knowfreq 40%

basics

~20 s

A credential helper is an external binary the Docker CLI calls to get credentials for a registry instead of reading them from its config file. Cloud registries issue short-lived tokens — ECR's lasts 12 hours — so a helper that mints a fresh one per call avoids expiry and stores no secret on disk.

open as a page

Describe the HTTP handshake a container client performs against a registry that uses token authentication: what the registry's 401 response and its `WWW-Authenticate: Bearer` header carry, and what the client does with them.

level: middleimportance: should knowfreq 42%

basics

~20 s

The client requests a resource, gets 401 with WWW-Authenticate: Bearer realm=..., service=..., scope=.... It calls that realm (the token service) with its credentials and the requested scope, receives a short-lived signed token listing allowed actions, then retries the original request with Authorization: Bearer <token>.

open as a page

What does the Docker daemon's `max-concurrent-downloads` setting control, and why does raising it often not speed a pull up?

level: middleimportance: should knowfreq 44%

basics

~20 s

It caps how many layer blobs the Docker daemon downloads in parallel for a pull, defaulting to 3 and set in daemon.json. Raising it adds streams, not bandwidth, and does nothing for extraction, which decompresses layers one at a time in order.

open as a page

After a successful `docker login`, where does the Docker CLI keep the credentials it will send on later pushes and pulls, and what are the security implications of the default behaviour?

level: middleimportance: should knowfreq 40%

basics

~20 s

By default it writes an entry to ~/.docker/config.json under auths, keyed by registry host, holding base64(username:password). That is encoding, not encryption, so anyone who reads the file has the credential. docker logout <host> removes the entry.

open as a page

Pushing a rebuilt version of an 800 MB image often transfers only a few megabytes, and copying that image to a second repository on the same registry can transfer nothing at all. What mechanisms make that possible?

level: middleimportance: should knowfreq 40%

basics

~20 s

Layers are content-addressed by SHA-256 digest, so before uploading the client asks the registry whether each digest already exists and skips those it has. Within one registry, a cross-repository blob mount links an existing blob into another repository, transferring zero bytes.

open as a page

Explain the Docker daemon's `registry-mirrors` setting in `/etc/docker/daemon.json`: what a pull-through cache registry does, which pulls it actually affects, and how you would stand one up.

level: middleimportance: should knowfreq 42%

basics

~20 s

A pull-through cache is a registry running in proxy mode: on a miss it fetches from upstream, stores the layers, and serves later requests locally. The daemon's registry-mirrors list only redirects Docker Hub (docker.io) pulls; other registries are unaffected and need per-registry configuration.

open as a page

What are the tradeoffs of pinning a Dockerfile's `FROM` base image to a sha256 digest instead of a version tag, and how do you keep such pins from going stale?

level: middleimportance: should knowfreq 45%

basics

~20 s

A digest pin makes builds reproducible and stops silent base-image changes, but it also freezes security patches and hides which version you are on. Write both — FROM img:3.12.4-slim@sha256:… — and let an automated dependency bot raise digest bumps as reviewable pull requests.

open as a page

Your pipeline builds an image once and needs to promote that exact artifact from a staging repository to a production repository, adding a release tag. How do you do that without rebuilding, and how do you prove it is the same image?

level: middleimportance: should knowfreq 45%

basics

~20 s

Copy or re-tag the existing manifest instead of rebuilding: docker buildx imagetools create -t prod-repo:1.4.2 staging-repo@sha256:…, or crane/skopeo copy. Prove sameness by comparing the sha256 manifest digest before and after — an identical digest means identical bytes.

open as a page

In `docker buildx build`, what does `--provenance=mode=max` record that `mode=min` does not?

level: seniorimportance: should knowfreq 44%

basics

~10 s

mode=min keeps the skeleton: builder identity, timestamps, source reference and output digest. mode=max adds the full build definition — Dockerfile, per-step metadata, resolved inputs, and every --build-arg value, which is how secrets leak.

open as a page

What does adding a registry host to the `insecure-registries` list in the Docker daemon's `daemon.json` actually change, and what would you do instead for a production internal registry?

level: seniorimportance: should knowfreq 34%

basics

~20 s

It tells the daemon to accept plain HTTP or an untrusted TLS certificate for that host, disabling verification. Credentials and images then travel unauthenticated and tamperable. In production, run the registry with real TLS and install your internal CA certificate on every node instead.

open as a page

A `docker pull` of a 1.87 GB image takes 4m12s on a fresh host and 38s on a warm one. How do you find where the time goes?

level: seniorimportance: should knowfreq 52%

basics

~20 s

Split the pull into transfer and extraction and measure each: whether seconds pile up under Downloading or Extracting, whether one layer dominates the manifest, the real throughput to the registry, and CPU and disk during unpacking. The warm host only reuses layers it already holds.

open as a page

A fleet of 40 CI build agents behind a single NAT gateway intermittently fails image pulls during peak hours with HTTP 429 from the registry. Walk through how you diagnose it and what you change so it stops recurring.

level: seniorimportance: should knowfreq 38%

basics

~20 s

Confirm it is registry throttling, not the network: check the 429 and remaining-quota headers, and whether pulls are anonymous. Then authenticate CI with a machine account, put a pull-through cache in front of the fleet, pin and pre-bake hot base images, and alert on 429 rate and cache hit ratio.

open as a page

Explain cosign's Sigstore 'keyless' signing flow: how a CI job signs a container image without holding any long-lived private key, where the resulting signature is stored, and what a verifier must check.

level: seniorimportance: should knowfreq 38%

basics

~20 s

CI presents its OIDC identity token; Fulcio returns a short-lived certificate binding that identity to an ephemeral key; cosign signs the image digest, logs the signature in the Rekor transparency log, and discards the private key. Verifiers check the certificate chain, the logged inclusion time, and the expected signer identity and issuer.

open as a page

Rolling back by redeploying the image tag `indexer:stable` brings the same broken build back. Why?

level: seniorimportance: should knowfreq 58%

basics

~20 s

Because the release already re-pointed that alias at the broken build, so redeploying it fetches the same manifest. A rollback has to name a tag nobody moved — the previous build's own immutable tag — not the alias the release just updated.

open as a page

How would you roll out `docker buildx` SBOM and provenance attestations across every service image?

level: principalimportance: should knowfreq 27%

basics

~20 s

Change the shared build path, not each pipeline: move builds onto an index-capable builder, default to minimal provenance everywhere and SBOM on published images, and keep mode=max for repositories whose build args you have audited.

open as a page

You operate one private container registry (Harbor or a cloud registry) for about a dozen product teams. Design the access model: who may push, who may pull, and how build pipelines and production hosts obtain credentials.

level: principalimportance: should knowfreq 28%

basics

~20 s

Namespace repositories per team, grant humans read-only plus break-glass, and give push rights only to machine identities scoped to their own namespace. Production pulls read-only, ideally via workload identity rather than stored secrets. Separate promotion namespaces, make release tags immutable, and set credential expiry and audit.

open as a page

Container image pulls dominate cold-start time across your fleet. Which levers do you pull, and what does each cost?

level: principalimportance: should knowfreq 38%

basics

~20 s

Measure pull time as a first-class signal, then pick among four levers: move fewer bytes, move them a shorter distance, move them before they are needed, or start before they all arrive. Each trades a different cost — staleness, a dependency, coupling, or money.

open as a page

You are asked to make signature verification mandatory before any container image runs in production, across many teams and with substantial third-party images in use. How do you roll that out, and what will break?

level: principalimportance: should knowfreq 28%

basics

~20 s

Enforce at admission, not in CI: a policy engine verifies signatures over digests against expected signer identities and rewrites tags to verified digests. Roll out in audit mode first, sign your own builds, mirror and re-sign third-party images internally, then fail closed per namespace with a documented break-glass path.

open as a page

Your platform deploys whatever the image tag `prod` currently points at. How do you govern that pointer, and would you keep the design?

level: principalimportance: should knowfreq 41%

basics

~20 s

A single mutable pointer with no history is a release control plane with no audit trail and no rollback target. Keep the alias for humans, restrict who may push it, record every move externally, and move deployments onto immutable build tags.

open as a page

You own image naming for an organisation with dozens of services and multiple environments. Design the tagging scheme — which tags exist, which may move, and what deployments actually reference — and justify the tradeoffs.

level: principalimportance: should knowfreq 35%

basics

~20 s

Split tags into immutable and rolling. Immutable: one per build, carrying the commit SHA and a semver release tag, never repushed. Rolling: 1, 1.4, stable, latest — convenience pointers only. Deployments reference digests; environments are recorded in a config repo, not encoded in image tags.

open as a page

showing 1–30 of 37