Skip to content

1.08 Docker Registry

Overview

A Docker Registry is a centralized storage and distribution system for Docker images. It is the source from which container images are pulled when running containers.

Abstract

Every Docker image must live somewhere before it can be run. That place is a registry β€” a server-side application that stores and serves image layers. Docker Hub (docker.io) is the default public registry, but cloud providers and self-hosted solutions offer private registries for internal images that should not be publicly accessible.


Why It Matters in Production

Without a registry strategy, teams push images ad hoc, lose track of versions, and risk pulling untrusted or outdated images in production. A well-managed registry ensures:

  • Consistent, versioned image delivery across environments
  • Access control over who can push or pull images
  • A single source of truth for all deployments

Key Concepts

Concept Description
Registry The server that stores and serves Docker images (e.g. docker.io, gcr.io)
Repository A named collection of related images within a registry (e.g. library/nginx)
Image name format <registry>/<user-or-account>/<image-name>
Official images Prefixed with library/ on Docker Hub; e.g. nginx β†’ docker.io/library/nginx
Tag A version label on an image (e.g. nginx:1.25, defaults to latest)
Private registry A registry with access controls requiring authentication to push or pull

Common Use Cases

  • Pulling public images from Docker Hub for local development and testing
  • Storing internal application images in a private registry (AWS ECR, GCP Artifact Registry, Azure ACR)
  • Running a self-hosted registry on-premise using the official registry:2 image
  • Tagging and pushing images to a local registry for air-gapped environments

Image Naming Convention

Docker image names follow this structure:

<registry>/<account-or-user>/<image-or-repository>

Examples:
  docker.io/library/nginx          # Official Docker Hub image
  gcr.io/kubernetes-e2e-test-images/dnsutils   # Google Container Registry
  private-registry.io/apps/internal-app        # Private registry

When no registry is specified, Docker defaults to docker.io. When no account is specified, it defaults to library (official images).


Example Configuration or Commands

Using a Public Registry (Docker Hub)

# Pull an official image (shorthand β€” Docker Hub is assumed)
docker run nginx

# Equivalent full image reference
docker run docker.io/library/nginx

Authenticating to a Private Registry

# Log in to a private registry
docker login private-registry.io

# Run a container from the private registry
docker run private-registry.io/apps/internal-app

Credential Storage

By default, Docker stores credentials unencrypted in ~/.docker/config.json. Use a credential helper (e.g. docker-credential-pass or OS keychain) in production to avoid plaintext secrets on disk.

Deploying a Self-Hosted Private Registry

# Run the official registry image on port 5000
docker run -d -p 5000:5000 --name registry registry:2
# Tag your local image for the local registry
docker image tag my-image localhost:5000/my-image

# Push to the local registry
docker push localhost:5000/my-image
# Pull from the same host
docker pull localhost:5000/my-image

# Pull from another host in the same network
docker pull 192.168.56.100:5000/my-image

Best Practices

Best Practices

  • Always use explicit image tags (e.g. nginx:1.25.3) β€” never rely on latest in production.
  • Mirror critical public images to a private registry to avoid rate limits and supply chain risks.
  • Use a managed registry service (ECR, GCR, ACR) for cloud workloads β€” they integrate natively with IAM and Kubernetes.
  • Automate image pushes through CI/CD pipelines β€” never push manually from developer machines to production registries.
  • Enable image vulnerability scanning in your registry (Trivy, Clair, or built-in cloud scanning).

Security Best Practices

Security

  • Always authenticate before pushing or pulling from a private registry β€” an unauthenticated pull will fail or expose a public image by mistake.
  • Never embed registry credentials in Dockerfiles, source code, or CI environment variables without a secrets manager.
  • Use TLS for any registry exposed over a network β€” the self-hosted registry:2 image serves HTTP by default; configure a reverse proxy (nginx/Traefik) with valid certificates.
  • Apply least-privilege IAM β€” CI pipelines should have push access; deployments should have pull-only access.
  • Rotate registry tokens and service account keys regularly.
  • Restrict public access to internal registries using VPC/private networking or firewall rules.

Do and Don't

βœ… Do ❌ Don't
Use a private registry for all internal images Push internal images to a public Docker Hub repo
Tag images with semantic versions or Git SHAs Use latest as the only tag in production
Log in before pulling from a private registry Assume Docker will prompt you automatically at runtime
Use TLS and authentication on self-hosted registries Expose a plain HTTP registry on a public network
Scan images for CVEs before promoting to production Deploy images directly from docker pull without validation
Use IAM roles for registry access in cloud environments Store registry passwords in plaintext config files

Common Mistakes

Common Mistakes

  • Forgetting to docker login before pulling from a private registry β€” results in an image-not-found error even if the image exists.
  • Using latest in production β€” makes rollbacks and debugging unpredictable.
  • No TLS on a self-hosted registry β€” Docker will refuse to push/pull unless the registry is listed as an insecure registry in /etc/docker/daemon.json.
  • Not mirroring public images β€” Docker Hub rate limits unauthenticated pulls (100/6h per IP); CI pipelines will fail unpredictably.
  • Pushing to the wrong registry β€” always verify the full image tag before running docker push.

Troubleshooting

# Check current login sessions
cat ~/.docker/config.json

# Test connectivity to a self-hosted registry
curl -v https://localhost:5000/v2/

# List images in a local registry
curl http://localhost:5000/v2/_catalog

# Inspect image tags in a repository
curl http://localhost:5000/v2/my-image/tags/list

# Re-authenticate if push/pull fails with 401
docker logout private-registry.io
docker login private-registry.io

# Allow insecure (HTTP) registry β€” add to /etc/docker/daemon.json
# { "insecure-registries": ["192.168.56.100:5000"] }
# Then restart Docker
sudo systemctl restart docker

Quick Recap

  • A Docker registry stores and distributes Docker images
  • Docker Hub (docker.io) is the default public registry; gcr.io is Google's
  • Image naming follows <registry>/<account>/<image> β€” omitting registry defaults to Docker Hub
  • Private registries require docker login before pulling or pushing
  • Deploy a self-hosted registry with registry:2 exposed on port 5000
  • Always use TLS, authentication, and image scanning in production registries

Interview / Revision Notes

  • What is a Docker registry? A server that stores Docker images and serves them on pull requests.
  • What is the default registry? Docker Hub β€” docker.io. The default account for official images is library.
  • Full image name for nginx? docker.io/library/nginx
  • How do you push to a private registry? Tag the image with the registry URL, docker login, then docker push.
  • How do you deploy a local private registry? docker run -d -p 5000:5000 --name registry registry:2
  • Why avoid latest in production? It is mutable β€” the same tag can point to different image content after a new push, making deployments non-deterministic.
  • Security risk with ~/.docker/config.json? Credentials are stored unencrypted by default; use a credential helper instead.