You have built a container image on your workstation. How do you deploy it to your production servers, and how do you make sure the whole team uses exactly the same version? The answer is a registry: a server that stores and distributes your images, like GitHub for code.
This lesson explains how a registry works under the hood, from layered storage to the pull and push protocol, then how to secure it: authentication, immutable references by digest, separated rights and image scanning. It is for anyone who publishes or consumes images, and prepares the lessons on signing and the supply chain.
What you will learn
- Explain what a registry is and its vocabulary (repository, tag, digest)
- Describe how an image is stored: the manifest and layers model
- Follow what
docker pullanddocker pushdo under the hood - Distinguish a mutable tag from an immutable digest, and choose the right one in production
- Choose a type of registry: public, cloud, private
- Apply the five security rules of a production registry
What is a container image registry?
A registry is the mandatory waypoint for any image between its build and its execution. Understanding what it stores, and under which name, is the basis of everything that follows, in particular the distinction between tag and digest.
Simple definition
A registry is a specialised storage server that stores container images, distributes them to whoever needs them and versions them with labels. It is, for images, what a Git forge is for source code.
Key vocabulary
Four terms come up constantly, and mixing them up leads to deployment errors. The table distinguishes them, with an example for each; the digest is the one that matters most for security.
| Term | Description | Example |
|---|---|---|
| Registry | Server that hosts images | Docker Hub, Harbor, AWS ECR |
| Repository | Space grouping all versions of the same image | nginx, my-app, postgres |
| Tag | Readable label that designates a version | 1.29.0, stable, latest |
| Digest | Unique and immutable SHA256 fingerprint of the content | sha256: followed by 64 hexadecimal characters |
Image vs container: the difference
An image is a static package, stored in the registry: it is the mould. A container is a running application, created from that image: it is the moulded object that runs. The registry only holds images, never containers.
Why use a registry?
Without a registry, you have to deploy by hand: copy the code, install dependencies, manage versions on every server. It quickly becomes unmanageable beyond a few servers, and every manual copy is an opportunity for drift between environments.
The 4 concrete benefits
A registry brings four benefits that become decisive as the team and the number of deployments grow. The last one, CI/CD integration, is what makes the other three automatic.
- Reproducibility: the same image everywhere, in development, staging and production. No more "works on my machine".
- Fast deployments: one build, N servers, and downloads sped up by layer deduplication.
- Traceability: who published which version, when, under which tag.
- CI/CD integration: the pipeline builds the image, pushes it to the registry, and the orchestrator (Kubernetes, Nomad) pulls it automatically.
Why does it work with Docker, Podman and Kubernetes?
You may use Docker, Podman, containerd or Kubernetes. These tools all talk to the same registry because they follow open standards: you can switch tools or registries without rewriting your scripts, and that avoids lock-in to a vendor.
The OCI standards (Open Container Initiative)
The container ecosystem relies on the specifications of the OCI (Open Container Initiative), which defines a common image format and distribution API, adopted by the whole ecosystem. Docker, Podman and containerd therefore talk to registries through the same HTTP endpoints /v2/..., and an image built with Docker runs in Kubernetes, which uses containerd under the hood.
The OCI publishes three specifications: the Image Spec (image format: manifests, layers, configuration), the Runtime Spec (how to run a container) and the Distribution Spec (the HTTP API to push and pull images). The Open Container Initiative website details them.
How is an image stored?
An image is not one big file: it is a layered system organised by a JSON manifest. This split explains both the speed of downloads and the integrity check.
The "manifest + layers" model
An image breaks down into three elements. The manifest is a JSON document that lists the image's components and their stacking order. The layers carry the filesystem content, each RUN or COPY instruction of a Dockerfile producing one. The config blob gathers the runtime metadata, including CMD, ENV and the default user.
Each layer is identified by its SHA256 digest. If two images share the same layer, for example the same base image, it is stored and downloaded only once: this is deduplication. It saves network and storage, and the SHA256 guarantees that a layer cannot be modified without its fingerprint changing.
How does docker pull work?
When you type docker pull nginx:1.29.0, the client follows five steps. Understanding them helps diagnose a slow download or an integrity error, and shows where layer verification happens.
- Manifest request: the client sends
GET /v2/library/nginx/manifests/1.29.0. - Manifest received: the registry answers with the list of layers and their SHA256.
- Missing layers download: the client only downloads the ones it does not already have locally.
- Verification: each layer is checked against its fingerprint; a single modified bit makes the download fail.
- Assembly: the client stacks the layers in order, and the image is ready to run.
How does docker push work?
The reverse process publishes a locally built image. It relies on the same deduplication: only the layers missing from the registry travel, which keeps successive publications of the same application light on the network.
The client computes the SHA256 of each layer, queries the registry with a HEAD request to know whether it already exists, uploads only the missing layers, then publishes the manifest with PUT /v2/.../manifests/<tag>. This last step binds the tag to the content: a tag is just a pointer to a manifest.
How do you secure access with authentication?
A registry can be public (anyone can pull images) or private (authentication required). In every case, publishing must be authenticated: whoever can push an image can get their code executed wherever it is deployed.
The Bearer Token scheme (Docker Registry v2 standard)
On a private registry, a request without authentication gets a 401 Unauthorized response with a WWW-Authenticate: Bearer realm="..." header pointing to the token service. The client authenticates there with its credentials, receives a bearer token, then replays its request with the Authorization: Bearer <token> header.
This token is deliberately short-lived: the Distribution specification sets its validity to 60 seconds by default. The scheme separates authentication (checking identity, including through LDAP, OAuth or OIDC) from authorisation (checking the right to pull or push on a given repository).
How do you read an image name?
The full name of an image follows a precise format, several parts of which are implicit. Knowing these defaults avoids pulling an image from an unexpected registry, a classic substitution vector:
[registry/][namespace/]repository[:tag|@digest]Concrete examples
The table breaks down common names. Note that nginx alone actually means docker.io/library/nginx:latest: a short name depends on the client configuration and on a mutable tag.
| Name | Registry | Namespace | Repository | Tag or digest |
|---|---|---|---|---|
nginx | docker.io (implicit) | library (implicit) | nginx | latest (implicit) |
nginx:1.29.0 | docker.io | library | nginx | 1.29.0 |
myorg/api:2.0.1 | docker.io | myorg | api | 2.0.1 |
harbor.example.com/prod/api:stable | harbor.example.com | prod | api | stable |
nginx@sha256:<digest> | docker.io | library | nginx | SHA256 digest |
Tags vs digests: the critical distinction
An image is referenced by a tag or by a digest, and this choice decides a deployment's reproducibility. It is the most important distinction of this lesson for supply chain security.
Tags (mutable)
A tag is mutable: latest, stable or even 1.2 can point to different images over time, and anyone allowed to push can move it. Handy to read and share, it does not guarantee that docker pull nginx:latest today gives the same image as tomorrow.
Digests (immutable)
A digest is immutable: sha256:... always designates the same image, bit for bit. It guarantees integrity and makes a deployment reproducible; its only drawback is being hard to read, with 64 hexadecimal characters. The image:tag@sha256:... form combines both: the tag for humans, the digest for machines.
Best practices
In production, the rule is simple: never latest, always at least a versioned tag, and preferably a digest. A redeployment that pulls a latest moved in the meantime can break the application, or install a compromised image.
Multi-architecture: one image, several platforms
Some images, such as nginx or alpine, exist for several platforms: linux/amd64, linux/arm64, sometimes windows/amd64. The same image name then serves machines of different architectures without the user having to pick a variant.
How does it work?
The registry stores a manifest index (or manifest list) that points to one manifest per platform. The client detects its system and architecture, then pulls the right manifest: a developer on an ARM64 Mac and an x86_64 server thus use the same reference. Beware: the digest of the index and that of a platform differ, which matters when you pin.
Which types of registries exist?
There are three families of registries: public, managed in the cloud and private self-hosted. The choice depends mostly on data sovereignty, integration with your cloud and the acceptable operational load.
Public registries
For open source, prototypes and sharing. Docker Hub's download limits are worth knowing: in CI, they are the first cause of unexpected failures, hence the value of a local cache.
| Registry | Characteristics | Limits |
|---|---|---|
| Docker Hub | Historical public registry, free for public images | 100 pulls per 6 h unauthenticated, 200 with a Personal account |
GitHub Container Registry (ghcr.io) | Integrated with GitHub Actions | Storage quotas depending on the plan |
| Quay.io (Red Hat) | Vulnerability scanning, automatic builds | Paid for private use |
Managed cloud registries
For companies already on a cloud: integration with the provider's IAM avoids managing separate credentials, and operations are delegated. Prices are indicative and vary by region and usage.
| Registry | Strengths | Indicative price |
|---|---|---|
| AWS ECR | IAM integration, vulnerability scanning | About $0.10 per GB per month |
| Google Artifact Registry | Multi-format (images, Maven, npm), scanning | About $0.10 per GB per month |
| Azure Container Registry | Geo-replication, AKS integration | From about $5 per month (Basic) |
Private on-premise registries
For data sovereignty, compliance or disconnected environments. The counterpart is operations: high availability, backups and updates remain your responsibility.
| Registry | Strengths | Complexity |
|---|---|---|
| Distribution (formerly Docker Registry) | Reference open source, simple | Basic, no graphical interface |
| Harbor | Interface, RBAC, built-in Trivy scanning, replication | Kubernetes deployment recommended |
| JFrog Artifactory | Multi-format, high availability, LDAP/SAML | Paid, complex setup |
| Sonatype Nexus | Multi-format, Maven-oriented | Java ecosystem |
A few selection guidelines: Docker Hub for a prototype, ghcr.io for CI/CD on GitHub, ECR on AWS, Harbor when compliance requires full control. The Docker Hub, Quay.io and Distribution guides (in French) detail each one.
What are the best practices for production?
Five rules cover the essentials of a production registry's security. They reinforce each other: an analysed image referenced by a mutable tag can be replaced after the analysis.
1. Never store secrets in images
A secret written in a layer stays readable with docker history or by extracting the layers, even if it is deleted in a later layer. The secret is injected at runtime, from a secrets manager, never at build time:
# ❌ BAD: the secret stays readable in a layer of the imageRUN echo "API_KEY=abc123" >> /app/.env# Kubernetes: the value comes from a Secret, never from the imageenv: - name: API_KEY valueFrom: secretKeyRef: name: api-credentials key: api-key2. Version images strictly
Strict versioning enables traceability, quick rollback and reproducibility. You publish semantic tags (1.2.3) or tags dated with the commit, never latest in production, and the deployment manifest references the digest:
spec: containers: - name: api image: harbor.example.com/prod/api:1.4.2@sha256:<digest>3. Use access tokens, not passwords
Access tokens can be revoked one by one, renewed easily and carry limited rights: a read-only token for deployments, a write token for CI only. Pass them through standard input, never as an argument visible in the shell history or the process list:
docker login registry.example.org -u robot-ci --password-stdin < "$TOKEN_FILE"Better still, in CI: a workload identity through OIDC replaces the long-lived token, as shown in the lesson OIDC: authenticating without a secret.
4. Separate pull and push rights
Least privilege applies to the registry: most consumers only need to pull. CI/CD pipelines push, production servers only pull, and developers pull from prod/* but push to dev/*. With Harbor, this translates into per-project roles:
Project "prod": developers = Guest (read only)Project "dev": developers = Developer (read and write)5. Scan images before deployment
You do not expose to production an image carrying critical known vulnerabilities. Trivy has been the scanner built into Harbor by default since version 2.2; Clair remains Quay's; Grype is another open source option. The recommended flow scans in staging, then promotes:
build the imagepush to the staging registryscan with Trivy or Grypeif a fixable critical vulnerability: fail the pipelineotherwise: promote to the production registry, by digestTroubleshooting: frequent problems
Registry errors look alike, but their cause shows in the HTTP code or the message. The table pairs the most frequent ones with their likely cause and their fix, without resorting to dangerous workarounds.
| Symptom | Likely cause | Solution |
|---|---|---|
401 Unauthorized | Expired or missing token | Log in again with docker login |
429 Too Many Requests | Docker Hub download limit | Authenticate, or go through a local cache |
manifest unknown | Missing tag or typo | List tags with crane ls |
| Slow download | Distant registry, no cache | Use a local cache (Harbor proxy) |
x509 certificate error | Unknown certificate authority | Add the authority to the trust store, rather than disabling TLS |
Key points
- A registry stores and distributes images centrally, like a Git forge for code.
- An image is a manifest and layers identified by their SHA256, deduplicated and checked on every download.
- The OCI standards make Docker, Podman and Kubernetes speak the same
/v2/protocol. - A tag is mutable, a digest is immutable: in production, reference by digest and refresh it regularly.
- A registry token is short-lived and separate from authorisation, which distinguishes pulling from pushing.
- Five rules in production: no secret in images, strict versioning, tokens rather than passwords, separated rights, scanning before promotion.
Knowledge check
Check that you have the essentials of this guide. The questions only cover what has just been explained here.
Knowledge check
Check what you have learned with this interactive quiz
How it works
- The timer starts when you click Start
- Multiple choice, true/false and short answer questions
- You can move between questions
- Detailed results are shown at the end
Starts the quiz and the timer
Review
(0/0)Score by domain
A domain groups several guides and gets several questions, so its score is more reliable than a per-topic score, which often rests on a single question.
Summary
Strengths
No topic passed at 80% on at least two questions yet.
Weak areas
No topic below the pass mark.
Recommended next
Hints before you try again?
Continue the course: Trivy: vulnerability, secret and IaC scanner
A new full quiz with random questions
Work again only on the questions you missed