container-registry-management

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Container Registry Management

容器镜像仓库管理

Overview

概述

Implement comprehensive container registry management including image scanning, vulnerability detection, retention policies, access control, and multi-region replication.
实现全面的容器镜像仓库管理,包括镜像扫描、漏洞检测、保留策略、访问控制和多区域复制。

When to Use

适用场景

  • Container image storage and distribution
  • Security scanning and compliance
  • Image retention and cleanup
  • Registry access control
  • Multi-region deployments
  • Image signing and verification
  • Cost optimization
  • 容器镜像存储与分发
  • 安全扫描与合规检查
  • 镜像保留与清理
  • 仓库访问控制
  • 多区域部署
  • 镜像签名与验证
  • 成本优化

Implementation Examples

实现示例

1. AWS ECR Setup and Management

1. AWS ECR 配置与管理

yaml
undefined
yaml
undefined

ecr-setup.yaml

ecr-setup.yaml

apiVersion: v1 kind: ConfigMap metadata: name: ecr-management namespace: operations data: setup-ecr.sh: | #!/bin/bash set -euo pipefail
REGISTRY_NAME="myapp"
REGION="us-east-1"
ACCOUNT_ID="123456789012"

echo "Setting up ECR repository..."

# Create ECR repository
aws ecr create-repository \
  --repository-name "$REGISTRY_NAME" \
  --region "$REGION" \
  --encryption-configuration encryptionType=KMS,kmsKey=arn:aws:kms:$REGION:$ACCOUNT_ID:key/12345678-1234-1234-1234-123456789012 \
  --image-tag-mutability IMMUTABLE \
  --image-scanning-configuration scanOnPush=true || true

echo "Repository: $ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com/$REGISTRY_NAME"

# Set lifecycle policy
aws ecr put-lifecycle-policy \
  --repository-name "$REGISTRY_NAME" \
  --region "$REGION" \
  --lifecycle-policy-text '{
    "rules": [
      {
        "rulePriority": 1,
        "description": "Keep last 20 images tagged with release",
        "selection": {
          "tagStatus": "tagged",
          "tagPrefixList": ["release"],
          "countType": "imageCountMoreThan",
          "countNumber": 20
        },
        "action": {
          "type": "expire"
        }
      },
      {
        "rulePriority": 2,
        "description": "Remove untagged images older than 7 days",
        "selection": {
          "tagStatus": "untagged",
          "countType": "sinceImagePushed",
          "countUnit": "days",
          "countNumber": 7
        },
        "action": {
          "type": "expire"
        }
      },
      {
        "rulePriority": 3,
        "description": "Keep all development images for 30 days",
        "selection": {
          "tagStatus": "tagged",
          "tagPrefixList": ["dev"],
          "countType": "sinceImagePushed",
          "countUnit": "days",
          "countNumber": 30
        },
        "action": {
          "type": "expire"
        }
      }
    ]
  }'

# Enable cross-region replication
aws ecr create-registry \
  --region "$REGION" \
  --replication-configuration '{
    "rules": [
      {
        "destinations": [
          {
            "region": "eu-west-1",
            "registryId": "'$ACCOUNT_ID'"
          },
          {
            "region": "ap-northeast-1",
            "registryId": "'$ACCOUNT_ID'"
          }
        ],
        "repositoryFilters": [
          {
            "filter": "'$REGISTRY_NAME'",
            "filterType": "PREFIX_MATCH"
          }
        ]
      }
    ]
  }' || true

echo "ECR setup complete"
scan-images.sh: | #!/bin/bash set -euo pipefail
REGISTRY_NAME="myapp"
REGION="us-east-1"

echo "Scanning all images in $REGISTRY_NAME"

# Get all image IDs
IMAGE_IDS=$(aws ecr list-images \
  --repository-name "$REGISTRY_NAME" \
  --region "$REGION" \
  --query 'imageIds[*]' \
  --output json)

# Scan each image
echo "$IMAGE_IDS" | jq -r '.[] | @base64' | while read image; do
  IMAGE=$(echo "$image" | base64 -d | jq -r '.imageTag')
  DIGEST=$(echo "$image" | base64 -d | jq -r '.imageDigest')

  echo "Scanning image: $IMAGE ($DIGEST)"

  # Start scan
  aws ecr start-image-scan \
    --repository-name "$REGISTRY_NAME" \
    --image-id imageTag="$IMAGE" \
    --region "$REGION" || true

  # Get scan results
  sleep 5
  RESULTS=$(aws ecr describe-image-scan-findings \
    --repository-name "$REGISTRY_NAME" \
    --image-id imageTag="$IMAGE" \
    --region "$REGION")

  CRITICAL=$(echo "$RESULTS" | jq '.imageScanFindings.findingSeverityCounts.CRITICAL // 0')
  HIGH=$(echo "$RESULTS" | jq '.imageScanFindings.findingSeverityCounts.HIGH // 0')

  if [ "$CRITICAL" -gt 0 ]; then
    echo "WARNING: Image has $CRITICAL critical vulnerabilities"
  fi

  if [ "$HIGH" -gt 0 ]; then
    echo "WARNING: Image has $HIGH high vulnerabilities"
  fi
done

echo "Image scanning complete"

apiVersion: v1 kind: ConfigMap metadata: name: ecr-management namespace: operations data: setup-ecr.sh: | #!/bin/bash set -euo pipefail
REGISTRY_NAME="myapp"
REGION="us-east-1"
ACCOUNT_ID="123456789012"

echo "Setting up ECR repository..."

# Create ECR repository
aws ecr create-repository \
  --repository-name "$REGISTRY_NAME" \
  --region "$REGION" \
  --encryption-configuration encryptionType=KMS,kmsKey=arn:aws:kms:$REGION:$ACCOUNT_ID:key/12345678-1234-1234-1234-123456789012 \
  --image-tag-mutability IMMUTABLE \
  --image-scanning-configuration scanOnPush=true || true

echo "Repository: $ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com/$REGISTRY_NAME"

# Set lifecycle policy
aws ecr put-lifecycle-policy \
  --repository-name "$REGISTRY_NAME" \
  --region "$REGION" \
  --lifecycle-policy-text '{
    "rules": [
      {
        "rulePriority": 1,
        "description": "Keep last 20 images tagged with release",
        "selection": {
          "tagStatus": "tagged",
          "tagPrefixList": ["release"],
          "countType": "imageCountMoreThan",
          "countNumber": 20
        },
        "action": {
          "type": "expire"
        }
      },
      {
        "rulePriority": 2,
        "description": "Remove untagged images older than 7 days",
        "selection": {
          "tagStatus": "untagged",
          "countType": "sinceImagePushed",
          "countUnit": "days",
          "countNumber": 7
        },
        "action": {
          "type": "expire"
        }
      },
      {
        "rulePriority": 3,
        "description": "Keep all development images for 30 days",
        "selection": {
          "tagStatus": "tagged",
          "tagPrefixList": ["dev"],
          "countType": "sinceImagePushed",
          "countUnit": "days",
          "countNumber": 30
        },
        "action": {
          "type": "expire"
        }
      }
    ]
  }'

# Enable cross-region replication
aws ecr create-registry \
  --region "$REGION" \
  --replication-configuration '{
    "rules": [
      {
        "destinations": [
          {
            "region": "eu-west-1",
            "registryId": "'$ACCOUNT_ID'"
          },
          {
            "region": "ap-northeast-1",
            "registryId": "'$ACCOUNT_ID'"
          }
        ],
        "repositoryFilters": [
          {
            "filter": "'$REGISTRY_NAME'",
            "filterType": "PREFIX_MATCH"
          }
        ]
      }
    ]
  }' || true

echo "ECR setup complete"
scan-images.sh: | #!/bin/bash set -euo pipefail
REGISTRY_NAME="myapp"
REGION="us-east-1"

echo "Scanning all images in $REGISTRY_NAME"

# Get all image IDs
IMAGE_IDS=$(aws ecr list-images \
  --repository-name "$REGISTRY_NAME" \
  --region "$REGION" \
  --query 'imageIds[*]' \
  --output json)

# Scan each image
echo "$IMAGE_IDS" | jq -r '.[] | @base64' | while read image; do
  IMAGE=$(echo "$image" | base64 -d | jq -r '.imageTag')
  DIGEST=$(echo "$image" | base64 -d | jq -r '.imageDigest')

  echo "Scanning image: $IMAGE ($DIGEST)"

  # Start scan
  aws ecr start-image-scan \
    --repository-name "$REGISTRY_NAME" \
    --image-id imageTag="$IMAGE" \
    --region "$REGION" || true

  # Get scan results
  sleep 5
  RESULTS=$(aws ecr describe-image-scan-findings \
    --repository-name "$REGISTRY_NAME" \
    --image-id imageTag="$IMAGE" \
    --region "$REGION")

  CRITICAL=$(echo "$RESULTS" | jq '.imageScanFindings.findingSeverityCounts.CRITICAL // 0')
  HIGH=$(echo "$RESULTS" | jq '.imageScanFindings.findingSeverityCounts.HIGH // 0')

  if [ "$CRITICAL" -gt 0 ]; then
    echo "WARNING: Image has $CRITICAL critical vulnerabilities"
  fi

  if [ "$HIGH" -gt 0 ]; then
    echo "WARNING: Image has $HIGH high vulnerabilities"
  fi
done

echo "Image scanning complete"

Terraform ECR configuration

Terraform ECR configuration

resource "aws_ecr_repository" "myapp" { name = "myapp" image_tag_mutability = "IMMUTABLE"
image_scanning_configuration { scan_on_push = true }
encryption_configuration { encryption_type = "KMS" kms_key = aws_kms_key.ecr.arn }
tags = { Name = "myapp-registry" } }
resource "aws_ecr_lifecycle_policy" "myapp" { repository = aws_ecr_repository.myapp.name
policy = jsonencode({ rules = [ { rulePriority = 1 description = "Keep last 20 production images" selection = { tagStatus = "tagged" tagPrefixList = ["release"] countType = "imageCountMoreThan" countNumber = 20 } action = { type = "expire" } }, { rulePriority = 2 description = "Remove untagged images after 7 days" selection = { tagStatus = "untagged" countType = "sinceImagePushed" countUnit = "days" countNumber = 7 } action = { type = "expire" } } ] }) }
resource "aws_ecr_repository_policy" "myapp" { repository = aws_ecr_repository.myapp.name
policy = jsonencode({ Version = "2012-10-17" Statement = [ { Effect = "Allow" Principal = { AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/EcsTaskExecutionRole" } Action = [ "ecr:GetDownloadUrlForLayer", "ecr:BatchGetImage", "ecr:GetImage" ] } ] }) }
undefined
resource "aws_ecr_repository" "myapp" { name = "myapp" image_tag_mutability = "IMMUTABLE"
image_scanning_configuration { scan_on_push = true }
encryption_configuration { encryption_type = "KMS" kms_key = aws_kms_key.ecr.arn }
tags = { Name = "myapp-registry" } }
resource "aws_ecr_lifecycle_policy" "myapp" { repository = aws_ecr_repository.myapp.name
policy = jsonencode({ rules = [ { rulePriority = 1 description = "Keep last 20 production images" selection = { tagStatus = "tagged" tagPrefixList = ["release"] countType = "imageCountMoreThan" countNumber = 20 } action = { type = "expire" } }, { rulePriority = 2 description = "Remove untagged images after 7 days" selection = { tagStatus = "untagged" countType = "sinceImagePushed" countUnit = "days" countNumber = 7 } action = { type = "expire" } } ] }) }
resource "aws_ecr_repository_policy" "myapp" { repository = aws_ecr_repository.myapp.name
policy = jsonencode({ Version = "2012-10-17" Statement = [ { Effect = "Allow" Principal = { AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/EcsTaskExecutionRole" } Action = [ "ecr:GetDownloadUrlForLayer", "ecr:BatchGetImage", "ecr:GetImage" ] } ] }) }
undefined

2. Container Image Build and Push

2. 容器镜像构建与推送

bash
#!/bin/bash
bash
#!/bin/bash

build-and-push.sh - Build and push container images

build-and-push.sh - 构建并推送容器镜像

set -euo pipefail
REGISTRY="${1:-123456789012.dkr.ecr.us-east-1.amazonaws.com}" IMAGE_NAME="${2:-myapp}" VERSION="${3:-latest}" DOCKERFILE="${4:-Dockerfile}"
echo "Building and pushing container image..."
set -euo pipefail
REGISTRY="${1:-123456789012.dkr.ecr.us-east-1.amazonaws.com}" IMAGE_NAME="${2:-myapp}" VERSION="${3:-latest}" DOCKERFILE="${4:-Dockerfile}"
echo "Building and pushing container image..."

Set full image path

设置完整镜像路径

FULL_IMAGE="$REGISTRY/$IMAGE_NAME:$VERSION"
FULL_IMAGE="$REGISTRY/$IMAGE_NAME:$VERSION"

Login to ECR

登录ECR

echo "Authenticating to ECR..." aws ecr get-login-password --region us-east-1 |
docker login --username AWS --password-stdin "$REGISTRY"
echo "Authenticating to ECR..." aws ecr get-login-password --region us-east-1 |
docker login --username AWS --password-stdin "$REGISTRY"

Build image

构建镜像

echo "Building image: $FULL_IMAGE" docker build
-f "$DOCKERFILE"
-t "$FULL_IMAGE"
-t "$REGISTRY/$IMAGE_NAME:latest"
--build-arg BUILD_DATE="$(date -u +'%Y-%m-%dT%H:%M:%SZ')"
--build-arg VCS_REF="$(git rev-parse --short HEAD)"
--build-arg VERSION="$VERSION"
.
echo "Building image: $FULL_IMAGE" docker build
-f "$DOCKERFILE"
-t "$FULL_IMAGE"
-t "$REGISTRY/$IMAGE_NAME:latest"
--build-arg BUILD_DATE="$(date -u +'%Y-%m-%dT%H:%M:%SZ')"
--build-arg VCS_REF="$(git rev-parse --short HEAD)"
--build-arg VERSION="$VERSION"
.

Scan with trivy before push

推送前使用Trivy扫描

echo "Scanning image with Trivy..." trivy image --severity HIGH,CRITICAL "$FULL_IMAGE"
echo "Scanning image with Trivy..." trivy image --severity HIGH,CRITICAL "$FULL_IMAGE"

Push image

推送镜像

echo "Pushing image to ECR..." docker push "$FULL_IMAGE" docker push "$REGISTRY/$IMAGE_NAME:latest"
echo "Pushing image to ECR..." docker push "$FULL_IMAGE" docker push "$REGISTRY/$IMAGE_NAME:latest"

Get image digest

获取镜像摘要

DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' "$FULL_IMAGE" | cut -d@ -f2)
echo "Image pushed successfully" echo "Image: $FULL_IMAGE" echo "Digest: $DIGEST"
undefined
DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' "$FULL_IMAGE" | cut -d@ -f2)
echo "Image pushed successfully" echo "Image: $FULL_IMAGE" echo "Digest: $DIGEST"
undefined

3. Image Signing with Notary

3. 使用Notary进行镜像签名

bash
#!/bin/bash
bash
#!/bin/bash

sign-image.sh - Sign container images with Notary

sign-image.sh - 使用Notary签名容器镜像

set -euo pipefail
IMAGE="${1}" NOTATION_KEY="${2:-mykey}"
echo "Signing image: $IMAGE"
set -euo pipefail
IMAGE="${1}" NOTATION_KEY="${2:-mykey}"
echo "Signing image: $IMAGE"

Initialize Notary

初始化Notary

notary key list
notary key list

Sign image

签名镜像

notation sign
--key "$NOTATION_KEY"
--allow-missing
"$IMAGE"
echo "Image signed successfully"
notation sign
--key "$NOTATION_KEY"
--allow-missing
"$IMAGE"
echo "Image signed successfully"

Verify signature

验证签名

notation verify "$IMAGE"
undefined
notation verify "$IMAGE"
undefined

4. Registry Access Control

4. 仓库访问控制

yaml
undefined
yaml
undefined

registry-access-control.yaml

registry-access-control.yaml

apiVersion: v1 kind: Secret metadata: name: ecr-pull-secret namespace: production type: kubernetes.io/dockercfg stringData: .dockercfg: | { "123456789012.dkr.ecr.us-east-1.amazonaws.com": { "auth": "base64-encoded-credentials", "email": "service-account@mycompany.com" } }

apiVersion: v1 kind: ServiceAccount metadata: name: ecr-pull-sa namespace: production imagePullSecrets:
  • name: ecr-pull-secret

apiVersion: v1 kind: Pod metadata: name: myapp namespace: production spec: serviceAccountName: ecr-pull-sa containers: - name: app image: 123456789012.dkr.ecr.us-east-1.amazonaws.com/myapp:latest imagePullPolicy: Always

apiVersion: v1 kind: Secret metadata: name: ecr-pull-secret namespace: production type: kubernetes.io/dockercfg stringData: .dockercfg: | { "123456789012.dkr.ecr.us-east-1.amazonaws.com": { "auth": "base64-encoded-credentials", "email": "service-account@mycompany.com" } }

apiVersion: v1 kind: ServiceAccount metadata: name: ecr-pull-sa namespace: production imagePullSecrets:
  • name: ecr-pull-secret

apiVersion: v1 kind: Pod metadata: name: myapp namespace: production spec: serviceAccountName: ecr-pull-sa containers: - name: app image: 123456789012.dkr.ecr.us-east-1.amazonaws.com/myapp:latest imagePullPolicy: Always

IAM policy for ECR access

IAM policy for ECR access

apiVersion: iam.aws.amazon.com/v1 kind: IAMPolicy metadata: name: ecr-read-only spec: policyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - ecr:GetDownloadUrlForLayer - ecr:BatchGetImage - ecr:GetImage - ecr:DescribeImages Resource: arn:aws:ecr::123456789012:repository/myapp - Effect: Allow Action: - ecr:GetAuthorizationToken Resource: ''
undefined
apiVersion: iam.aws.amazon.com/v1 kind: IAMPolicy metadata: name: ecr-read-only spec: policyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - ecr:GetDownloadUrlForLayer - ecr:BatchGetImage - ecr:GetImage - ecr:DescribeImages Resource: arn:aws:ecr::123456789012:repository/myapp - Effect: Allow Action: - ecr:GetAuthorizationToken Resource: ''
undefined

5. Registry Monitoring

5. 仓库监控

yaml
undefined
yaml
undefined

registry-monitoring.yaml

registry-monitoring.yaml

apiVersion: v1 kind: ConfigMap metadata: name: registry-monitoring namespace: monitoring data: dashboards.json: | { "dashboard": { "title": "Container Registry", "panels": [ { "title": "Images by Repository", "targets": [ { "expr": "count by (repository) (aws_ecr_repository_images)" } ] }, { "title": "Images with Vulnerabilities", "targets": [ { "expr": "sum(aws_ecr_image_scan_findings{severity=~"HIGH|CRITICAL"})" } ] }, { "title": "Registry Storage", "targets": [ { "expr": "aws_ecr_repository_size_bytes" } ] } ] } }

apiVersion: v1 kind: ConfigMap metadata: name: registry-alerts namespace: monitoring data: alerts.yaml: | groups: - name: registry_alerts rules: - alert: ImageWithCriticalVulnerabilities expr: aws_ecr_image_scan_findings{severity="CRITICAL"} > 0 for: 5m labels: severity: critical annotations: summary: "Image has critical vulnerabilities"
      - alert: ImagePushFailure
        expr: aws_ecr_push_failures_total > 0
        for: 1m
        labels:
          severity: warning
        annotations:
          summary: "Image push failed"

      - alert: RegistryStorageHigh
        expr: aws_ecr_repository_size_bytes / 1024 / 1024 / 1024 > 100
        labels:
          severity: warning
        annotations:
          summary: "Registry storage usage is high"
undefined
apiVersion: v1 kind: ConfigMap metadata: name: registry-monitoring namespace: monitoring data: dashboards.json: | { "dashboard": { "title": "Container Registry", "panels": [ { "title": "Images by Repository", "targets": [ { "expr": "count by (repository) (aws_ecr_repository_images)" } ] }, { "title": "Images with Vulnerabilities", "targets": [ { "expr": "sum(aws_ecr_image_scan_findings{severity=~"HIGH|CRITICAL"})" } ] }, { "title": "Registry Storage", "targets": [ { "expr": "aws_ecr_repository_size_bytes" } ] } ] } }

apiVersion: v1 kind: ConfigMap metadata: name: registry-alerts namespace: monitoring data: alerts.yaml: | groups: - name: registry_alerts rules: - alert: ImageWithCriticalVulnerabilities expr: aws_ecr_image_scan_findings{severity="CRITICAL"} > 0 for: 5m labels: severity: critical annotations: summary: "Image has critical vulnerabilities"
      - alert: ImagePushFailure
        expr: aws_ecr_push_failures_total > 0
        for: 1m
        labels:
          severity: warning
        annotations:
          summary: "Image push failed"

      - alert: RegistryStorageHigh
        expr: aws_ecr_repository_size_bytes / 1024 / 1024 / 1024 > 100
        labels:
          severity: warning
        annotations:
          summary: "Registry storage usage is high"
undefined

Best Practices

最佳实践

✅ DO

✅ 建议

  • Scan images before deployment
  • Use image tag immutability
  • Implement retention policies
  • Control registry access with IAM
  • Sign images for verification
  • Replicate across regions
  • Monitor registry storage
  • Use private registries
  • 部署前扫描镜像
  • 使用镜像标签不可变性
  • 实施保留策略
  • 使用IAM控制仓库访问
  • 签名镜像以进行验证
  • 跨区域复制镜像
  • 监控仓库存储
  • 使用私有仓库

❌ DON'T

❌ 不建议

  • Push to public registries
  • Use
    latest
    tag in production
  • Allow anonymous pulls
  • Store secrets in images
  • Keep old images indefinitely
  • Push without scanning
  • Use default credentials
  • Share registry credentials
  • 推送到公共仓库
  • 生产环境使用
    latest
    标签
  • 允许匿名拉取
  • 在镜像中存储密钥
  • 无限期保留旧镜像
  • 未扫描就推送镜像
  • 使用默认凭证
  • 共享仓库凭证

Registry Options

仓库选项

  • Docker Hub: Public registry
  • AWS ECR: AWS-managed
  • Google GCR: Google Cloud
  • Azure ACR: Azure-managed
  • Artifactory: Self-hosted
  • Harbor: Open-source
  • Docker Hub: 公共仓库
  • AWS ECR: AWS托管
  • Google GCR: 谷歌云托管
  • Azure ACR: Azure托管
  • Artifactory: 自托管
  • Harbor: 开源仓库

Image Naming Convention

镜像命名规范

[registry]/[organization]/[repository]:[tag]
123456789012.dkr.ecr.us-east-1.amazonaws.com/myapp:v1.2.3
[registry]/[organization]/[repository]:[tag]
123456789012.dkr.ecr.us-east-1.amazonaws.com/myapp:v1.2.3

Resources

参考资源