如何通过Lambda函数在同账号同区域复制ECR镜像标签?
解决ECR跨仓库镜像复制的LayersNotFoundException问题
问题背景
需要通过Lambda函数将同账号同区域下两个ECR仓库的指定镜像标签复制:dev-repo(开发测试用)到release-repo(发布用),要做成WebAPI因此不使用命令行的PULL/TAG/PUSH流程。尝试用AWS.ECR的putImage() API实现,但执行时抛出LayersNotFoundException,提示目标仓库缺少镜像所需的层。
原错误代码片段:
const ecr = new AWS.ECR({ apiVersion: '2015-09-21', region: 'ap-northeast-1' }); var params3 = { imageIds: [ { imageTag: "latest" } ], repositoryName: "dev-repo" }; await ecr.batchGetImage(params3, function(err, data) { console.log(`[log] batchGetImage ----`); console.log(data.images[0].imageId); if (err) console.log(err, err.stack); else { console.log(data); _imageManifest = data.images[0].imageManifest; _imageDigest = data.images[0].imageId.imageDigest; _imageTag = data.images[0].imageId.imageTag; _imageManifestMediaType = data.images[0].imageManifestMediaType; _registryId = data.images[0].registryId; } }).promise(); var params4 = { imageManifest: _imageManifest, repositoryName: 'release-repo', imageDigest: _imageDigest, imageManifestMediaType: _imageManifestMediaType, imageTag: _imageTag, registryId: _registryId }; await ecr.putImage(params4, function(err, data) { console.log(`[log] putImage ----`); if (err) console.log(err, err.stack); else console.log(data); }).promise();
错误信息:
{ "errorType": "LayersNotFoundException", "errorMessage": "Layers with digests '[sha256:bf06eb87a616c35c96a20d27e321d128c8ffa3d3043be450e4cde55c40ae1234,sha256:b06e123492282da4881988d86ce029772688c184c8e3d4be8ca57324c132d914,...]' required for pushing image into repository with name 'release-repo' in the registry with id 'xxxxxxx' do not exist", "trace": [...] }
错误原因
putImage() API的设计目标是向目标仓库上传镜像清单(manifest),但要求镜像的所有层已经存在于目标仓库中。当前场景下,镜像层仅存在于源仓库dev-repo,目标仓库release-repo无对应层,因此触发该错误。正确的做法是使用ECR专门提供的**copyImage() API**,它会自动处理镜像层的跨仓库复制,无需手动处理清单。
修正后的Lambda代码
const AWS = require('aws-sdk'); const ecr = new AWS.ECR({ apiVersion: '2015-09-21', region: 'ap-northeast-1' }); exports.handler = async (event) => { try { const copyParams = { sourceImageTag: "latest", // 源镜像标签 sourceRepositoryName: "dev-repo", // 源仓库名称 destinationRepositoryName: "release-repo", // 目标仓库名称 registryId: "你的AWS账号ID", // 同账号场景可省略,跨账号需填写源账号ID destinationImageTag: "latest" // 目标镜像标签,可自定义 }; const copyResult = await ecr.copyImage(copyParams).promise(); console.log("镜像复制成功:", copyResult); return { statusCode: 200, body: JSON.stringify({message: "镜像复制成功", image: copyResult.imageId}) }; } catch (err) { console.error("镜像复制失败:", err); return { statusCode: 500, body: JSON.stringify({error: err.message}) }; } };
权限配置
确保Lambda执行角色拥有以下权限(添加到角色的IAM策略中):
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ecr:CopyImage", "ecr:BatchGetImage", "ecr:GetDownloadUrlForLayer" ], "Resource": [ "arn:aws:ecr:ap-northeast-1:你的账号ID:repository/dev-repo", "arn:aws:ecr:ap-northeast-1:你的账号ID:repository/release-repo" ] } ] }
补充说明
copyImage()支持同账号/跨账号、同区域/跨区域的镜像复制,参数配置灵活。- 如果需要复制特定镜像摘要(digest)而非标签,可以将
sourceImageTag替换为sourceImageDigest。 - 原代码中同时混用了回调函数和
async/await,会导致变量赋值时机异常,修正后的代码统一使用async/await处理异步操作,避免逻辑冲突。
内容的提问来源于stack exchange,提问作者Ray
相关产品推荐
相关产品推荐

