Container Registry Setup Expert
Эксперт по настройке и управлению container registries.
Типы Registry
Cloud-Managed
| Registry |
Provider |
Features |
| ECR |
AWS |
IAM integration, scanning |
| Artifact Registry |
GCP |
Multi-format, regional |
| ACR |
Azure |
AD integration, geo-rep |
| Docker Hub |
Docker |
Public/private, CI/CD |
Self-Hosted
| Registry |
Best For |
Features |
| Harbor |
Enterprise |
RBAC, scanning, replication |
| Nexus |
Multi-artifact |
Maven, npm, Docker |
| Artifactory |
Enterprise |
Universal, HA |
| Distribution |
Simple |
Official Docker registry |
AWS ECR Setup
Terraform Configuration
resource "aws_ecr_repository" "app" {
name = "my-application"
image_tag_mutability = "IMMUTABLE"
image_scanning_configuration {
scan_on_push = true
}
encryption_configuration {
encryption_type = "KMS"
kms_key = aws_kms_key.ecr.arn
}
tags = {
Environment = "production"
Team = "platform"
}
}
resource "aws_ecr_lifecycle_policy" "cleanup" {
repository = aws_ecr_repository.app.name
policy = jsonencode({
rules = [
{
rulePriority = 1
description = "Keep last 10 images"
selection = {
tagStatus = "tagged"
tagPrefixList = ["v"]
countType = "imageCountMoreThan"
countNumber = 10
}
action = {
type = "expire"
}
},
{
rulePriority = 2
description = "Remove untagged after 7 days"
selection = {
tagStatus = "untagged"
countType = "sinceImagePushed"
countUnit = "days"
countNumber = 7
}
action = {
type = "expire"
}
}
]
})
}
ECR Authentication
# Login 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
# Push image
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
Harbor Self-Hosted
Docker Compose Setup
version: '3'
services:
harbor-core:
image: goharbor/harbor-core:v2.9.0
container_name: harbor-core
env_file:
- ./common/config/core/env
volumes:
- ./common/config/core/certificates:/etc/core/certificates
- ./common/config/core/key:/etc/core/key
depends_on:
- registry
- redis
- postgresql
networks:
- harbor
registry:
image: goharbor/registry-photon:v2.9.0
container_name: registry
volumes:
- registry_data:/storage
- ./common/config/registry:/etc/registry
networks:
- harbor
postgresql:
image: goharbor/harbor-db:v2.9.0
container_name: harbor-db
volumes:
- database:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
networks:
- harbor
redis:
image: goharbor/redis-photon:v2.9.0
container_name: harbor-redis
volumes:
- redis:/var/lib/redis
networks:
- harbor
nginx:
image: goharbor/nginx-photon:v2.9.0
container_name: nginx
ports:
- "80:8080"
- "443:8443"
volumes:
- ./common/config/nginx:/etc/nginx
depends_on:
- harbor-core
networks:
- harbor
volumes:
registry_data:
database:
redis:
networks:
harbor:
driver: bridge
Image Security
Vulnerability Scanning
# Trivy scan
trivy image myapp:latest
# Grype scan
grype myapp:latest
# ECR scan results
aws ecr describe-image-scan-findings \
--repository-name myapp \
--image-id imageTag=latest
Image Signing with Cosign
# Generate key pair
cosign generate-key-pair
# Sign image
cosign sign --key cosign.key myregistry/myapp:latest
# Verify signature
cosign verify --key cosign.pub myregistry/myapp:latest
Content Trust (Docker)
# Enable content trust
export DOCKER_CONTENT_TRUST=1
# Sign and push
docker push myregistry/myapp:latest
# Verify on pull
docker pull myregistry/myapp:latest
Kubernetes Integration
Image Pull Secret
apiVersion: v1
kind: Secret
metadata:
name: registry-credentials
namespace: default
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: |
eyJhdXRocyI6eyJteXJlZ2lzdHJ5LmNvbSI6eyJ1c2VybmFtZSI6InVzZXIi
LCJwYXNzd29yZCI6InBhc3MiLCJhdXRoIjoiZFhObGNqcHdZWE56In19fQ==
Deployment with Pull Secret
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: myregistry.com/myapp:v1.0.0
imagePullPolicy: Always
imagePullSecrets:
- name: registry-credentials
ServiceAccount Configuration
apiVersion: v1
kind: ServiceAccount
metadata:
name: myapp-sa
namespace: default
imagePullSecrets:
- name: registry-credentials
CI/CD Integration
GitHub Actions
name: Build and Push
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to ECR
uses: aws-actions/amazon-ecr-login@v2
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: |
123456789.dkr.ecr.us-east-1.amazonaws.com/myapp:${{ github.sha }}
myuser/myapp:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
GitLab CI
stages:
- build
- push
variables:
IMAGE_NAME: $CI_REGISTRY_IMAGE
build:
stage: build
image: docker:24
services:
- docker:24-dind
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
script:
- docker build -t $IMAGE_NAME:$CI_COMMIT_SHA .
- docker push $IMAGE_NAME:$CI_COMMIT_SHA
only:
- main
Cleanup Scripts
ECR Cleanup
import boto3
from datetime import datetime, timedelta
def cleanup_untagged_images(repository: str, days_old: int = 7):
"""Remove untagged images older than specified days."""
ecr = boto3.client('ecr')
response = ecr.describe_images(
repositoryName=repository,
filter={'tagStatus': 'UNTAGGED'}
)
cutoff = datetime.now() - timedelta(days=days_old)
images_to_delete = []
for image in response['imageDetails']:
if image['imagePushedAt'].replace(tzinfo=None) < cutoff:
images_to_delete.append({
'imageDigest': image['imageDigest']
})
if images_to_delete:
ecr.batch_delete_image(
repositoryName=repository,
imageIds=images_to_delete
)
print(f"Deleted {len(images_to_delete)} images")
# Usage
cleanup_untagged_images('my-app', days_old=7)
Performance Optimization
Registry Caching
# Docker daemon.json
{
"registry-mirrors": ["https://mirror.gcr.io"],
"insecure-registries": [],
"max-concurrent-downloads": 10,
"max-concurrent-uploads": 5
}
Pull-Through Cache (Harbor)
# Harbor project config
replication:
- name: docker-hub-proxy
type: pull-through
source: https://registry-1.docker.io
filters:
- name: library/*
trigger:
type: manual
Troubleshooting
# Test connectivity
curl -v https://myregistry.com/v2/
# Check authentication
docker login myregistry.com
# Verify TLS
openssl s_client -connect myregistry.com:443 -servername myregistry.com
# Clear credentials
docker logout myregistry.com
rm ~/.docker/config.json
# Debug pull issues
docker pull myregistry.com/myapp:latest --debug
Лучшие практики
- Image immutability — используйте immutable tags
- Vulnerability scanning — scan on push обязателен
- Lifecycle policies — автоматическая очистка старых images
- Content trust — подписывайте production images
- Geo-replication — для global deployments
- Access control — минимальные права через RBAC
- Monitoring — алерты на failed pushes и pulls