Managing Registries and Artifacts
The container registry is the "source of truth" for your deployments. In a professional DevOps environment, relying solely on public Docker Hub repositories is rarely sufficient due to security requirements, rate limiting, and the need to protect proprietary code.
This guide covers the strategies for managing private registries, implementing robust tagging schemes, and ensuring the security of your stored artifacts.
1. Beyond Docker Hub: Private Registries
While Docker Hub is the default registry, enterprise workflows require private storage.
Reasons to switch to a private registry:
Security: Host proprietary code that cannot be public.
Performance: Pulling images from a registry in the same cloud region (e.g., AWS ECR to AWS EC2) is significantly faster and cheaper (lower data transfer costs) than pulling from the public internet.
Availability: You are not dependent on Docker Hub's uptime or rate limits (Docker Hub strictly limits pulls for anonymous users).
Types of Private Registries
Cloud-Managed Registries (Recommended): Most teams should use the registry provided by their cloud vendor. They offer built-in integration with IAM (Identity and Access Management) and high availability.
AWS: Amazon Elastic Container Registry (ECR)
Google Cloud: Google Artifact Registry (GAR) or Container Registry (GCR)
Azure: Azure Container Registry (ACR)
Self-Hosted Enterprise Registries: For on-premises environments or specific compliance needs.
Harbor: An open-source, CNCF-graduated registry with advanced security features (scanning, signing).
JFrog Artifactory / Sonatype Nexus: "Universal" artifact repositories that store Docker images alongside Java JARs, npm packages, etc.
Simple Self-Hosted:
- Docker Distribution (Registry v2): The reference implementation. You can run it as a container (
docker run -p 5000:5000 registry:2). Useful for local caching or simple setups, but lacks a UI and advanced role management.
- Docker Distribution (Registry v2): The reference implementation. You can run it as a container (
2. Naming and Authentication
When using a private registry, the image name changes. Docker assumes any image without a URL prefix belongs to Docker Hub.
Docker Hub (Implicit):
ubuntu:latest->library/ubuntu:latestPrivate Registry (Explicit):
<registry-domain>/<project>/<image>:<tag>
Example (AWS ECR): 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-app:v1.0
Authentication (docker login)
Before pushing or pulling, you must authenticate.
Standard:
docker login registry.example.com(Prompts for username/password).Cloud Helpers: Cloud CLIs often handle the login token generation for you.
AWS:
aws ecr get-login-password | docker login --username AWS --password-stdin ...GCP:
gcloud auth configure-docker(Configures Docker to use your gcloud credentials automatically).
3. Advanced Tagging Strategies
How you tag your images determines your ability to rollback, debug, and release reliably.
The Trap of :latest
Never deploy :latest to production.
It is mutable: The tag moves every time you push. You have no guarantee that
latesttoday is the same code aslatestyesterday.It is ambiguous: Looking at a running container, you cannot tell which version of the code is inside if the tag is just
latest.
Strategy A: Semantic Versioning (SemVer)
Tag images with human-readable release numbers: v1.0.0, v1.0.1, v1.1.0.
Pros: Easy for humans to understand. Good for public releases.
Cons: Requires a manual or automated "release" step to increment the number.
Strategy B: Git Commit SHA (The Golden Standard)
Tag images with the first 7-8 characters of the Git commit hash: git-a1b2c3d.
Pros: Traceability. You know exactly which line of code is in the container. If a container fails, you check the tag, go to GitHub/GitLab, and view that commit.
Pros: Immutability. A Git commit hash never changes.
Recommended Hybrid Strategy:
CI Build: Automatically tag every build with the Git SHA (
myapp:git-a1b2c3d).Promotion: When that specific image passes all tests and is ready for release, add a SemVer tag to it (
myapp:v1.0.0).
Image Promotion Pattern (Build Once, Tag Many)
Anti-Pattern: Rebuilding the image for production. (e.g., running docker build in dev, then running docker build again in prod). Risk: The dependencies might have changed in the 5 minutes between builds.
Best Practice (Promotion):
Build the image once in the CI pipeline.
Tag it with the Git SHA.
Push to the registry.
Test that specific image.
If tests pass, retag that existing image for production.
# 1. Pull the tested artifact (identified by hash)
docker pull [myregistry.com/app:git-a1b2c3d](https://myregistry.com/app:git-a1b2c3d)
# 2. Retag it for release
docker tag [myregistry.com/app:git-a1b2c3d](https://myregistry.com/app:git-a1b2c3d) [myregistry.com/app:v1.0.0](https://myregistry.com/app:v1.0.0)
# 3. Push the new tag (no data transfer needed, just metadata update)
docker push [myregistry.com/app:v1.0.0](https://myregistry.com/app:v1.0.0)4. Registry Maintenance and Security
Vulnerability Scanning
Modern registries (Harbor, ECR, ACR, Docker Hub Pro) have built-in vulnerability scanners (often based on Clair or Trivy).
Action: Configure your registry to "Scan on Push."
Policy: Set a policy that prevents pulling images with "Critical" vulnerabilities.
Immutable Tags
Some registries allow you to mark tags as immutable.
- If you configure
v*tags to be immutable, no one can overwritev1.0.0with a different image. This prevents accidental (or malicious) overwrites of released software.
Garbage Collection (Lifecycle Policies)
Images accumulate quickly. If you build on every commit, you will have thousands of images consuming storage costs.
Lifecycle Policy: Configure rules to automatically delete old images.
Example: "Keep the last 10 images tagged
v*."Example: "Delete any untagged images (dangling) older than 7 days."
Image Signing (Content Trust)
How do you ensure the image you pull wasn't tampered with (Man-in-the-Middle attack)?
Docker Content Trust (Notary): Uses digital signatures. You sign the image with a private key; the Docker client verifies it with a public key.
Cosign (Sigstore): A modern, increasingly popular tool for signing containers, blobs, and other artifacts.
# Example of signing with Cosign
cosign sign --key cosign.key [myregistry.com/app:v1.0.0](https://myregistry.com/app:v1.0.0)