Private Registry Setup
Private Registry Setup
Docker Registry (Official)
The simplest way to run a private registry:
# Run registry container
docker run -d -p 5000:5000 --name registry \
-v registry_data:/var/lib/registry \
registry:2
# Tag and push image
docker tag myapp:latest localhost:5000/myapp:latest
docker push localhost:5000/myapp:latest
# Pull image
docker pull localhost:5000/myapp:latest
# List images in registry
curl http://localhost:5000/v2/_catalog
# {"repositories":["myapp"]}
Registry with Authentication
# Create htpasswd file
mkdir -p auth
apt-get install apache2-utils
htpasswd -Bbn admin secret123 > auth/htpasswd
# Run registry with auth
docker run -d -p 5000:5000 --name registry \
-v registry_data:/var/lib/registry \
-v $(pwd)/auth:/auth \
-e "REGISTRY_AUTH=htpasswd" \
-e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
-e "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd" \
registry:2
# Log in
docker login localhost:5000
# Username: admin
# Password: secret123
Registry with TLS
# Generate self-signed certificate
mkdir -p certs
docker run --rm \
-v $(pwd)/certs:/certs \
-e "REGISTRY_HTTP_ADDR=0.0.0.0:443" \
-e "REGISTRY_HTTP_TLS_CERTIFICATE=/certs/cert.pem" \
-e "REGISTRY_HTTP_TLS_KEY=/certs/key.pem" \
registry:2
# Or use Let's Encrypt with certbot
certbot certonly --standalone -d registry.company.com
# Run with TLS
docker run -d -p 443:443 --name registry \
-v registry_data:/var/lib/registry \
-v /etc/letsencrypt:/etc/letsencrypt \
-e "REGISTRY_HTTP_ADDR=0.0.0.0:443" \
-e "REGISTRY_HTTP_TLS_CERTIFICATE=/etc/letsencrypt/live/registry.company.com/fullchain.pem" \
-e "REGISTRY_HTTP_TLS_KEY=/etc/letsencrypt/live/registry.company.com/privkey.pem" \
registry:2
Docker Compose for Registry
services:
registry:
image: registry:2
ports:
- "443:443"
environment:
REGISTRY_HTTP_ADDR: "0.0.0.0:443"
REGISTRY_HTTP_TLS_CERTIFICATE: /certs/cert.pem
REGISTRY_HTTP_TLS_KEY: /certs/key.pem
REGISTRY_AUTH: htpasswd
REGISTRY_AUTH_HTPASSWD_REALM: "Registry Realm"
REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd
volumes:
- registry_data:/var/lib/registry
- ./certs:/certs:ro
- ./auth:/auth:ro
volumes:
registry_data:
Cloud Container Registries
Cloud Container Registries
Amazon ECR (Elastic Container Registry)
# Create repository
aws ecr create-repository --repository-name myapp --region us-east-1
# Log in to ECR
aws ecr get-login-password --region us-east-1 | \
docker login --username AWS --password-stdin \
123456789.dkr.ecr.us-east-1.amazonaws.com
# Tag and push
docker tag myapp:latest 123456789.dkr.ecr.us-east-1.amazonaws.com/myapp:latest
docker push 123456789.dkr.ecr.us-east-1.amazonaws.com/myapp:latest
# Lifecycle policy (auto-delete old images)
aws ecr put-lifecycle-policy \
--repository-name myapp \
--lifecycle-policy-text '{
"rules": [{
"rulePriority": 1,
"description": "Keep last 10 images",
"selection": {
"tagStatus": "any",
"countType": "imageCountMoreThan",
"countNumber": 10
},
"action": {"type": "expire"}
}]
}'
Google Container Registry (GCR)
# Authenticate
gcloud auth configure-docker
# Tag and push
docker tag myapp:latest gcr.io/my-project/myapp:latest
docker push gcr.io/my-project/myapp:latest
# Or use Artifact Registry (newer)
artifactregistry repositories create my-repo --repository-format=docker
docker tag myapp:latest us-central1-docker.pkg.dev/my-project/my-repo/myapp:latest
docker push us-central1-docker.pkg.dev/my-project/my-repo/myapp:latest
Azure Container Registry (ACR)
# Create ACR
az acr create --name myregistry --sku Standard
# Log in
az acr login --name myregistry
# Tag and push
docker tag myapp:latest myregistry.azurecr.io/myapp:latest
docker push myregistry.azurecr.io/myapp:latest
# Enable admin access (for simple auth)
az acr update -n myregistry --admin-enabled true
Docker Hub (Private)
# Log in
docker login
# Push to personal repo
docker tag myapp:latest username/myapp:latest
docker push username/myapp:latest
# Push to organization
docker tag myapp:latest myorg/myapp:latest
docker push myorg/myapp:latest
Registry Comparison
| Registry | Free Tier | Auth | Vulnerability Scanning |
|---|---|---|---|
| Docker Hub | 1 private repo | Token | Docker Scout |
| ECR | 500MB/month free | IAM | Inspector |
| GCR | 500MB free | IAM | Container Analysis |
| ACR | 100MB free | Azure AD | Defender |
| Harbor | Self-hosted | OIDC/LDAP | Trivy/S Clair |
Registry Maintenance
Registry Maintenance
Garbage Collection
Remove unused image layers from the registry:
# Stop registry
docker stop registry
# Run garbage collection
docker run --rm \
-v registry_data:/var/lib/registry \
registry:2 \
registry garbage-collect /etc/docker/registry/config.yml
# Restart registry
docker start registry
# Automated garbage collection (cron)
0 2 * * * docker run --rm -v registry_data:/var/lib/registry registry:2 registry garbage-collect /etc/docker/registry/config.yml
Image Retention Policies
# docker-compose.yml with retention
services:
registry:
image: registry:2
environment:
REGISTRY_STORAGE_DELETE_ENABLED: "true"
# Delete specific image by digest
curl -X DELETE http://localhost:5000/v2/myapp/manifests/sha256:abc123...
Registry Health Check
# Check registry health
curl http://localhost:5000/v2/
# {}
# List all repositories
curl http://localhost:5000/v2/_catalog
# List tags for a repository
curl http://localhost:5000/v2/myapp/tags/list
# Get image manifest
curl -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
http://localhost:5000/v2/myapp/manifests/latest
Backup Registry Data
# Backup registry volumes
docker run --rm \
-v registry_data:/source:ro \
-v $(pwd):/backup \
alpine tar czf /backup/registry-backup.tar.gz -C /source .
# Restore
docker volume create registry_data_restored
docker run --rm \
-v registry_data_restored:/target \
-v $(pwd):/backup \
alpine tar xzf /backup/registry-backup.tar.gz -C /target
Registry Mirroring
// /etc/docker/daemon.json
{
"registry-mirrors": ["https://registry-mirror.company.com"]
}
# Pull images through mirror automatically
docker pull nginx:1.25
# Docker checks mirror first, falls back to Docker Hub