Master container image distribution with Docker registries, including Docker Hub, private registries, and enterprise registry solutions.
Container registries are central repositories for storing and distributing Docker images. Understanding how to work with registries is essential for container deployment workflows, whether using public registries like Docker Hub or deploying private registries for enterprise environments.
A container registry stores tagged images organized by repositories, enabling teams to share images across development, testing, and production environments. Registries implement the OCI Distribution Specification, providing standardized APIs for pushing, pulling, and managing container images.
Container registries follow a hierarchical structure for organizing images:
Registry Components:
Image Naming Convention:
1[registry/][namespace/]repository[:tag|@digest]
2
3Examples:
4nginx # Official image, latest tag
5nginx:1.25-alpine # Specific tag
6myuser/myapp:v1.0.0 # User namespace
7gcr.io/project/app:sha-abc123 # Custom registry
8myapp@sha256:abc123... # By digest (immutable)Registry Types:
Understanding the registry architecture enables efficient image distribution across environments.
Docker Hub is the default public registry and the largest repository of container images. It provides both free and paid tiers with features for individual developers and organizations.
Docker Hub Features:
Rate Limits:
Best Practices:
Running a private Docker registry provides complete control over image storage, security, and distribution. The official Docker Registry is a stateless, highly scalable server-side application.
Use Cases for Private Registry:
Registry Configuration:
Deployment Options:
Securing your container registry is critical for protecting proprietary images and ensuring only authorized users can push or pull images.
Security Layers:
Authentication Methods:
TLS Configuration:
For production, always use TLS. Self-signed certificates require configuring Docker daemon to trust them, or use certificates from a trusted CA.
Managing a registry involves monitoring storage, garbage collection, replication, and ensuring high availability.
Operational Tasks:
Garbage Collection:
Registry doesn't automatically delete blobs when images are deleted. Garbage collection removes unreferenced data.
High Availability:
Mirror/Proxy Cache:
Configure registry as a pull-through cache to reduce external bandwidth and improve performance.
Deploy a secure private registry with authentication, configure it for CI/CD pipelines, and set up automated image scanning.
1# Complete Private Registry Setup
2# docker-compose.yml for production registry
3
4version: '3.8'
5
6services:
7 registry:
8 image: registry:2
9 container_name: docker-registry
10 restart: always
11 ports:
12 - "5000:5000"
13 environment:
14 REGISTRY_AUTH: htpasswd
15 REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd
16 REGISTRY_AUTH_HTPASSWD_REALM: "Registry Realm"
17 REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /var/lib/registry
18 REGISTRY_STORAGE_DELETE_ENABLED: "true"
19 REGISTRY_HTTP_TLS_CERTIFICATE: /certs/registry.crt
20 REGISTRY_HTTP_TLS_KEY: /certs/registry.key
21 REGISTRY_HTTP_DEBUG_ADDR: "0.0.0.0:5001"
22 REGISTRY_HTTP_DEBUG_PROMETHEUS_ENABLED: "true"
23 volumes:
24 - ./auth:/auth
25 - ./certs:/certs:ro
26 - registry-data:/var/lib/registry
27 healthcheck:
28 test: ["CMD", "wget", "-q", "--spider", "http://localhost:5000/v2/"]
29 interval: 30s
30 timeout: 10s
31 retries: 3
32 networks:
33 - registry-network
34
35 # Web UI for registry
36 registry-ui:
37 image: joxit/docker-registry-ui:latest
38 container_name: registry-ui
39 restart: always
40 ports:
41 - "8080:80"
42 environment:
43 REGISTRY_TITLE: "Private Docker Registry"
44 REGISTRY_URL: https://registry:5000
45 SINGLE_REGISTRY: "true"
46 DELETE_IMAGES: "true"
47 SHOW_CONTENT_DIGEST: "true"
48 depends_on:
49 - registry
50 networks:
51 - registry-network
52
53 # Vulnerability scanner
54 trivy:
55 image: aquasec/trivy:latest
56 container_name: trivy-scanner
57 volumes:
58 - trivy-cache:/root/.cache/
59 command: server --listen 0.0.0.0:8081
60 ports:
61 - "8081:8081"
62 networks:
63 - registry-network
64
65volumes:
66 registry-data:
67 driver: local
68 trivy-cache:
69 driver: local
70
71networks:
72 registry-network:
73 driver: bridge
74
75---
76# CI/CD Integration Script (ci-registry.sh)
77#!/bin/bash
78set -e
79
80# Configuration
81REGISTRY="registry.company.com:5000"
82IMAGE_NAME="myapp"
83TRIVY_SERVER="http://trivy:8081"
84
85# Get version from git
86VERSION=${CI_COMMIT_TAG:-${CI_COMMIT_SHORT_SHA:-latest}}
87
88# Full image reference
89FULL_IMAGE="$REGISTRY/$IMAGE_NAME:$VERSION"
90
91echo "Building $FULL_IMAGE"
92
93# Build image
94docker build -t $FULL_IMAGE .
95
96# Scan for vulnerabilities
97echo "Scanning image for vulnerabilities..."
98trivy image --server $TRIVY_SERVER \
99 --severity HIGH,CRITICAL \
100 --exit-code 1 \
101 $FULL_IMAGE
102
103# Login to registry
104echo "$REGISTRY_PASSWORD" | docker login $REGISTRY \
105 --username $REGISTRY_USER --password-stdin
106
107# Push image
108docker push $FULL_IMAGE
109
110# Tag as latest if this is a release
111if [[ "$CI_COMMIT_TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
112 docker tag $FULL_IMAGE $REGISTRY/$IMAGE_NAME:latest
113 docker push $REGISTRY/$IMAGE_NAME:latest
114fi
115
116# Sign image with cosign
117cosign sign --key cosign.key $FULL_IMAGE
118
119echo "Successfully pushed and signed $FULL_IMAGE"
120
121---
122# Kubernetes ImagePullSecret (registry-secret.yaml)
123apiVersion: v1
124kind: Secret
125metadata:
126 name: registry-credentials
127 namespace: production
128type: kubernetes.io/dockerconfigjson
129data:
130 .dockerconfigjson: <base64-encoded-docker-config>
131
132---
133# Generate the secret
134kubectl create secret docker-registry registry-credentials \
135 --docker-server=registry.company.com:5000 \
136 --docker-username=admin \
137 --docker-password=secretpassword \
138 --namespace=production
139
140---
141# Use in deployment (deployment.yaml)
142apiVersion: apps/v1
143kind: Deployment
144metadata:
145 name: myapp
146spec:
147 template:
148 spec:
149 imagePullSecrets:
150 - name: registry-credentials
151 containers:
152 - name: app
153 image: registry.company.com:5000/myapp:v1.0.0
154
155---
156# GitHub Actions workflow (.github/workflows/docker.yml)
157name: Build and Push
158
159on:
160 push:
161 branches: [main]
162 tags: ['v*']
163
164jobs:
165 build:
166 runs-on: ubuntu-latest
167 steps:
168 - uses: actions/checkout@v4
169
170 - name: Set up Docker Buildx
171 uses: docker/setup-buildx-action@v3
172
173 - name: Login to Registry
174 uses: docker/login-action@v3
175 with:
176 registry: registry.company.com:5000
177 username: ${{ secrets.REGISTRY_USER }}
178 password: ${{ secrets.REGISTRY_PASSWORD }}
179
180 - name: Extract metadata
181 id: meta
182 uses: docker/metadata-action@v5
183 with:
184 images: registry.company.com:5000/myapp
185 tags: |
186 type=ref,event=branch
187 type=semver,pattern={{version}}
188 type=sha,prefix=
189
190 - name: Build and push
191 uses: docker/build-push-action@v5
192 with:
193 context: .
194 push: true
195 tags: ${{ steps.meta.outputs.tags }}
196 labels: ${{ steps.meta.outputs.labels }}
197 cache-from: type=registry,ref=registry.company.com:5000/myapp:cache
198 cache-to: type=registry,ref=registry.company.com:5000/myapp:cache,mode=max
199
200 - name: Scan image
201 uses: aquasecurity/trivy-action@master
202 with:
203 image-ref: registry.company.com:5000/myapp:${{ github.sha }}
204 exit-code: '1'
205 severity: 'HIGH,CRITICAL'Your progress is saved in this browser, on this device only.