Registries: pushing and pulling images

Docker · Practical · 10 min

Registries are how images move from your build to servers, CI and teammates.

A registry stores and serves images. Docker Hub (docker.io) is the default; others include GitHub Container Registry (ghcr.io), GitLab's registry, cloud registries (Amazon ECR, Google Artifact Registry, Azure ACR) and self-hosted ones such as Harbor.

The image name says where it goes: ghcr.io/acme/api:1.4.2 means registry ghcr.io, repository acme/api, tag 1.4.2. To push, the local image must carry that name:

docker login ghcr.io
docker tag api:1.4.2 ghcr.io/acme/api:1.4.2
docker push ghcr.io/acme/api:1.4.2

Pushes and pulls are layer-based: layers the registry already has, such as your base image's layers, aren't uploaded again.

Authentication: docker login stores credentials in a credential helper (the OS keychain on Desktop) or, failing that, in ~/.docker/config.json. Use access tokens rather than passwords, and short-lived tokens in CI.

Tags vs digests: a tag is mutable; someone can push a different image under 1.4.2 tomorrow. The digest (ghcr.io/acme/api@sha256:...), printed after each push, is the content hash and can never change. Pin digests in production manifests when you need guaranteed reproducibility; tools such as Renovate keep them updated.

Docker Hub limits: anonymous and free-account pulls are rate-limited. CI systems that pull a lot should authenticate, use a pull-through cache or mirror, or pull base images from another registry.

Private repositories require docker login on every machine that pulls them, including servers and CI runners.

Example

echo "$GHCR_TOKEN" | docker login ghcr.io -u my-user --password-stdin
docker build -t ghcr.io/acme/api:1.4.2 -t ghcr.io/acme/api:latest .
docker push ghcr.io/acme/api:1.4.2
# 1.4.2: digest: sha256:7c3e...a1f9 size: 1784
docker push ghcr.io/acme/api:latest       # layers already exist: instant

# Pull an exact, immutable image
docker pull ghcr.io/acme/api@sha256:7c3e...a1f9
docker image inspect ghcr.io/acme/api:1.4.2 --format '{{json .RepoDigests}}'
docker logout ghcr.io

Remember

  • The registry host is part of the image name; tag images to match before pushing
  • Push/pull transfer only missing layers
  • Tags can be overwritten; digests are immutable
  • Authenticate CI to avoid Docker Hub rate limits

Watch out for

  • Passing a password with -p on the command line, where it lands in shell history — use --password-stdin.

Check yourself

  1. You push api:1.4.2 to a registry, and later a colleague pushes a different build with the same tag. Which reference still gets your original image?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.docker.com/reference/cli/docker/image/push/