本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
将 Amazon ECR 容器镜像复制到各处 AWS 账户 AWS 区域
Faisal Shahdad,Amazon Web Services
Summary
此模式向您展示了如何使用无服务器方法将带标签的图像从现有的 Amazon Elastic Container Registry (Amazon ECR) 存储库复制到其他和。 AWS 账户 AWS 区域该解决方案 AWS Step Functions 用于管理复制工作流程和复制大型容器映像的 AWS Lambda 功能。
Amazon ECR 使用原生跨区域和跨账户复制功能,可以跨区域和账户复制容器映像。但是这些功能只能从开启复制的那一刻起复制映像。目前没有机制能够将现有映像复制到不同区域和账户。
这种模式可以帮助人工智能 (AI) 团队向其他账户和区域分发容器化机器学习 (ML) 模型、框架(例如 PyTorch TensorFlow、和 Hugging Face)以及依赖关系。这可以帮助您克服服务限制并优化 GPU 计算资源。您也可以选择性地从特定来源账户和地区复制 Amazon ECR 存储库。有关更多信息,请参阅 Amazon ECR 中的跨区域复制已实现。
先决条件和限制
先决条件
两个或更多活跃账户 AWS 账户 (至少有一个源账户和一个目标账户)
所有账户都有相应的 AWS Identity and Access Management (IAM) 权限
用于构建 Lambda 容器映像的 Docker
AWS Command Line Interface (AWS CLI) 已为所有账户配置
限制
未标记的映像排除- 该解决方案仅复制具有显式标签的容器映像。它会跳过摘要中存在的未加标签的 SHA256 映像。
Lambda 执行超时限制 — AWS Lambda 限制为最长 15 分钟的执行超时,这可能不足以复制大型容器映像或存储库。
手动管理容器映像 — crane-app.py Python 代码需要重新构建和重新部署 Lambda 容器映像。
并行处理容量有限 — MaxConcurrency 状态设置限制了您可以同时复制的存储库数量。但是,您可以在来源账户的 AWS CloudFormation 模板中修改此设置。请注意,较高的并发值可能会导致您超过服务速率限制和账户级 Lambda 执行配额。
架构
目标堆栈
该模式有四个主要组成部分:
源账户基础架构 — 创建编排组件的 CloudFormation 模板
目标账户基础设施- 创建跨账户访问角色的 CloudFormation 模板
Lambda 函数 — 基于 Python 的函数,使用 Crane 进行高效的映像复制
容器映像 – 将 Lambda 函数与所需工具打包在一起的 Docker 容器
目标架构
Step Function 工作流
Step Functions 状态机会编排以下内容,如下图所示:
PopulateRepositoryList— 扫描 Amazon ECR 存储库并填充 Amazon DynamoDB
GetRepositoryList— 从 DynamoDB 检索唯一的存储库列表
DeduplicateRepositories— 确保没有重复处理
CopyRepositories— 处理存储库的并行复制
NotifySuccess/NotifyFailure – 基于执行结果的 Amazon Simple Notification Service(Amazon SNS)通知
Amazon 工具
其他工具
代码存储库
最佳实践
遵循最低权限原则,并授予执行任务所需的最低权限。有关详情,请参阅 IAM 文档中的授予最低权限和安全最佳实践。
操作说明
| Task | 说明 | 所需技能 |
|---|
配置 AWS CLI 配置文件。 | 配置源账户配置文件: aws configure --profile source-account
# Enter: Access Key ID, Secret Access Key, Default region, Output format (json)
配置目标账户配置文件: aws configure --profile destination-account
# Enter: Access Key ID, Secret Access Key, Default region, Output format (json)
验证配置: aws sts get-caller-identity --profile source-account
aws sts get-caller-identity --profile destination-account
| DevOps 工程师、数据工程师、机器学习工程师 |
收集所需信息。 | 获取源账户 ID: export SOURCE_ACCOUNT_ID=$(aws sts get-caller-identity --profile source-account --query Account --output text)
echo "Source Account ID: $SOURCE_ACCOUNT_ID"
获取目标账户 ID: export DEST_ACCOUNT_ID=$(aws sts get-caller-identity --profile destination-account --query Account --output text)
echo "Destination Account ID: $DEST_ACCOUNT_ID"
设置 AWS 区域. 修改您所在地区的以下命令: export SOURCE_REGION="us-east-1"
export DEST_REGION="us-east-2"
列出源账户中现有的 Amazon ECR 存储库: aws ecr describe-repositories --profile source-account --region $SOURCE_REGION --query 'repositories[].repositoryName' --output table
| DevOps 工程师、数据工程师、机器学习工程师 |
克隆存储库。 | 将项目的 存储库克隆到本地工作站。 git clone https://github.com/aws-samples/sample-ecr-copy
| DevOps 工程师、数据工程师、机器学习工程师 |
| Task | 说明 | 所需技能 |
|---|
验证模版。 | 验证 CloudFormation 模板: aws cloudformation validate-template \
--template-body file://"Destination Account cf_template.yml" \
--profile destination-account
| DevOps 工程师、机器学习工程师、数据工程师 |
部署目标基础设施。 | 部署目标账户堆栈: aws cloudformation deploy \
--template-file "Destination Account cf_template.yml" \
--stack-name ecr-copy-destination \
--parameter-overrides \
SourceAccountId=$SOURCE_ACCOUNT_ID \
SourceRoleName=ECRContainerLambdaRole \
--capabilities CAPABILITY_NAMED_IAM \
--profile destination-account \
--region $DEST_REGION
等待堆栈删除完成。 aws cloudformation wait stack-create-complete \
--stack-name ecr-copy-destination \
--profile destination-account \
--region $DEST_REGION
| 数据工程师、机器学习工程师、 DevOps 工程师 |
验证部署。 | 获取堆栈输出: aws cloudformation describe-stacks \
--stack-name ecr-copy-destination \
--profile destination-account \
--region $DEST_REGION \
--query 'Stacks[0].Outputs' \
--output table
存储跨账户 IAM 角色: export CROSS_ACCOUNT_ROLE_ARN=$(aws cloudformation describe-stacks \
--stack-name ecr-copy-destination \
--profile destination-account \
--region $DEST_REGION \
--query 'Stacks[0].Outputs[?OutputKey==`CrossAccountRoleArn`].OutputValue' \
--output text)
echo "Cross-Account Role ARN: $CROSS_ACCOUNT_ROLE_ARN"
| DevOps 工程师、机器学习工程师、数据工程师 |
| Task | 说明 | 所需技能 |
|---|
准备容器构建。 | 验证 Docker 是否正在运行: docker --version
docker info
确保 crane-app.py 和 Dockerfile 位于当前目录中: ls -la crane-app.py Dockerfile
| 数据工程师、机器学习工程师、 DevOps 工程师 |
构建容器映像。 | 构建 Lambda 容器映像: docker build -t ecr-copy-lambda . --no-cache
验证映像是否已创建: docker images ecr-copy-lambda
(可选)在本地测试容器: docker run --rm --entrypoint python ecr-copy-lambda -c "import boto3; print('Container working')"
| 数据工程师、机器学习工程师、 DevOps 工程师 |
创建存储库并上传映像。 | 在源账户中创建 Amazon ECR 存储库: aws ecr create-repository \
--repository-name ecr-copy-lambda \
--profile source-account \
--region $SOURCE_REGION
获取 Amazon ECR 登录令牌并对 Docker 进行身份验证: aws ecr get-login-password \
--profile source-account \
--region $SOURCE_REGION | \
docker login --username AWS --password-stdin \
$SOURCE_ACCOUNT_ID.dkr.ecr.$SOURCE_REGION.amazonaws.com
为 Amazon ECR 的图片添加标签: docker tag ecr-copy-lambda:latest \
$SOURCE_ACCOUNT_ID.dkr.ecr.$SOURCE_REGION.amazonaws.com/ecr-copy-lambda:latest
将映像上传到 Amazon S3 docker push $SOURCE_ACCOUNT_ID.dkr.ecr.$SOURCE_REGION.amazonaws.com/ecr-copy-lambda:latest
存储映像 URI 以备后用: export LAMBDA_IMAGE_URI="$SOURCE_ACCOUNT_ID.dkr.ecr.$SOURCE_REGION.amazonaws.com/ecr-copy-lambda:latest"
echo "Lambda Image URI: $LAMBDA_IMAGE_URI"
| 数据工程师、机器学习工程师、 DevOps 工程师 |
Verify the image. | 列出存储库中的映像: aws ecr list-images \
--repository-name ecr-copy-lambda \
--profile source-account \
--region $SOURCE_REGION
获取映像详情: aws ecr describe-images \
--repository-name ecr-copy-lambda \
--profile source-account \
--region $SOURCE_REGION
| 数据工程师、机器学习工程师、 DevOps 工程师 |
| Task | 说明 | 所需技能 |
|---|
准备部署参数。 | 设置通知电子邮件: export NOTIFICATION_EMAIL="your-email@company.com"
定义要复制的存储库(以逗号分隔): export REPOSITORY_LIST="app-frontend,app-backend,database-migrations"
设置环境: export ENVIRONMENT="dev"
echo "Deployment Parameters:"
echo "Source Account: $SOURCE_ACCOUNT_ID"
echo "Destination Account: $DEST_ACCOUNT_ID"
echo "Source Region: $SOURCE_REGION"
echo "Destination Region: $DEST_REGION"
echo "Lambda Image: $LAMBDA_IMAGE_URI"
echo "Notification Email: $NOTIFICATION_EMAIL"
echo "Repositories: $REPOSITORY_LIST"
| 数据工程师、 DevOps 工程师、机器学习工程师 |
验证源模版。 | 验证源 CloudFormation 模板: aws cloudformation validate-template \
--template-body file://"Source Account Cf template.yml" \
--profile source-account
| 数据工程师、机器学习工程师、 DevOps 工程师 |
部署源基础设施。 | 部署源账户堆栈: aws cloudformation deploy \
--template-file "Source Account Cf template.yml" \
--stack-name ecr-copy-source \
--parameter-overrides \
SourceAccountId=$SOURCE_ACCOUNT_ID \
DestinationAccountId=$DEST_ACCOUNT_ID \
DestinationRegion=$DEST_REGION \
SourceRegion=$SOURCE_REGION \
NotificationEmail=$NOTIFICATION_EMAIL \
RepositoryList="$REPOSITORY_LIST" \
LambdaImageUri=$LAMBDA_IMAGE_URI \
Environment=$ENVIRONMENT \
--capabilities CAPABILITY_NAMED_IAM \
--profile source-account \
--region $SOURCE_REGION
等待堆栈完成(这可能需要 10 分钟): aws cloudformation wait stack-create-complete \
--stack-name ecr-copy-source \
--profile source-account \
--region $SOURCE_REGION
| 数据工程师、机器学习工程师、 DevOps 工程师 |
验证部署并收集输出。 | 获取堆栈输出: aws cloudformation describe-stacks \
--stack-name ecr-copy-source \
--profile source-account \
--region $SOURCE_REGION \
--query 'Stacks[0].Outputs' \
--output table
存储状态机和 SNS 主题的 Amazon 资源名称 (ARNs): export STATE_MACHINE_ARN=$(aws cloudformation describe-stacks \
--stack-name ecr-copy-source \
--profile source-account \
--region $SOURCE_REGION \
--query 'Stacks[0].Outputs[?OutputKey==`StateMachineArn`].OutputValue' \
--output text)
export SNS_TOPIC_ARN=$(aws cloudformation describe-stacks \
--stack-name ecr-copy-source \
--profile source-account \
--region $SOURCE_REGION \
--query 'Stacks[0].Outputs[?OutputKey==`SNSTopicArn`].OutputValue' \
--output text)
echo "State Machine ARN: $STATE_MACHINE_ARN"
echo "SNS Topic ARN: $SNS_TOPIC_ARN"
| DevOps 工程师、机器学习工程师、数据工程师 |
确认电子邮件订阅。 | 查看您的电子邮件以确认您的 SNS 订阅。 在电子邮件中选择确认链接。 验证订阅状态。 aws sns list-subscriptions-by-topic \
--topic-arn $SNS_TOPIC_ARN \
--profile source-account \
--region $SOURCE_REGION
| 数据工程师、机器学习工程师、 DevOps 工程师 |
| Task | 说明 | 所需技能 |
|---|
运行并监控复制过程 | | DevOps 工程师、机器学习工程师、数据工程师 |
运行 Step Function。 | 生成唯一的名称: export EXECUTION_NAME="ecr-copy-$(date +%Y%m%d-%H%M%S)"
运行 Step Function。 export EXECUTION_ARN=$(aws stepfunctions start-execution \
--state-machine-arn $STATE_MACHINE_ARN \
--name $EXECUTION_NAME \
--profile source-account \
--region $SOURCE_REGION \
--query 'executionArn' \
--output text)
echo "Execution started: $EXECUTION_ARN"
echo "Execution Name: $EXECUTION_NAME"
| DevOps 工程师、机器学习工程师、数据工程师 |
监控进度。 | 检查状态:
aws stepfunctions describe-execution \
--execution-arn $EXECUTION_ARN \
--profile source-account \
--region $SOURCE_REGION \
--query '{Status:status,StartDate:startDate,StopDate:stopDate}' \
--output table
获取历史记录:
aws stepfunctions get-execution-history \
--execution-arn $EXECUTION_ARN \
--profile source-account \
--region $SOURCE_REGION \
--query 'events[?type==`TaskStateEntered` || type==`TaskSucceeded` || type==`TaskFailed`].{Type:type,Timestamp:timestamp,Details:stateEnteredEventDetails.name}' \
--output table
| DevOps 工程师、机器学习工程师、数据工程师 |
检查结果。 | 等待该过程完成(每 30 秒更新一次): while true; do
STATUS=$(aws stepfunctions describe-execution \
--execution-arn $EXECUTION_ARN \
--profile source-account \
--region $SOURCE_REGION \
--query 'status' \
--output text)
echo "Current status: $STATUS"
if [[ "$STATUS" == "SUCCEEDED" || "$STATUS" == "FAILED" || "$STATUS" == "TIMED_OUT" || "$STATUS" == "ABORTED" ]]; then
break
fi
sleep 30
done
echo "Final execution status: $STATUS"
| DevOps 工程师、机器学习工程师、数据工程师 |
验证映像。 | 列出目标账户中的存储库: aws ecr describe-repositories \
--profile destination-account \
--region $DEST_REGION \
--query 'repositories[].repositoryName' \
--output table
检查存储库映像: for repo in $(echo $REPOSITORY_LIST | tr ',' ' '); do
echo "\nImages in repository: $repo"
aws ecr list-images \
--repository-name $repo \
--profile destination-account \
--region $DEST_REGION \
--query 'imageIds[].imageTag' \
--output table 2>/dev/null || echo "Repository $repo not found or no images"
done
| DevOps 工程师、数据工程师、机器学习工程师 |
问题排查
| 问题 | 解决方案 |
|---|
Step Function 无法运行。 | 要从历史记录中检索详细的故障事件,请运行以下 AWS CLI 命令: if [[ "$STATUS" == "FAILED" ]]; then
echo "Getting failure details..."
aws stepfunctions get-execution-history \
--execution-arn $EXECUTION_ARN \
--profile source-account \
--region $SOURCE_REGION \
--query 'events[?type==`TaskFailed`]' \
--output json
fi
要检索失败的 Lambda 函数的日志,请运行以下 AWS CLI 命令: # Check Lambda function logs
echo "\nLambda function logs:"
aws logs describe-log-groups \
--log-group-name-prefix "/aws/lambda/ecr-copy-source" \
--profile source-account \
--region $SOURCE_REGION \
--query 'logGroups[].logGroupName' \
--output table
|
相关资源
附加信息
配置参数
参数 | 说明 | 示例 |
|---|
SourceAccountId
| 来源 AWS 账户 ID | 11111111111
|
DestinationAccountId
| 目的地 AWS 账户 ID | 22222222222
|
DestinationRegion
| 目标 AWS 区域 | us-east-2
|
SourceRegion
| 来源 AWS 区域 | us-east-1
|
NotificationEmail
| 电子邮件通知 | abc@xyz.com
|
RepositoryList
| 要复制的存储库 | repo1,repo2,repo3
|
LambdaImageUri
| Lambda 容器映像 | ${ACCOUNT}.dkr.ecr.${REGION}.amazonaws.com/ecr-copy-lambda:latest
|