跨账号删除含镜像ECR的CloudFormation栈失败求助
跨账号删除含ECR镜像的CloudFormation栈问题解决办法
问题场景
跨账号通过CodePipeline删除CloudFormation栈时触发DELETE_FAILED错误,原因是栈内ECR仓库存在镜像,无法直接删除,错误信息如下:
The repository with name 'x' in registry with id '111199999' cannot be deleted because it still contains images.
你考虑的跨账号Lambda清理镜像再删栈的方案是可行的,下面给出优化后的实现步骤,同时提供更贴合CloudFormation生命周期的替代方案:
方案一:简化版跨账号Lambda清理流程
直接改造现有CodePipeline,在删除栈前新增镜像清理步骤:
- 配置跨账号Lambda权限:在ECR所在目标账号创建Lambda函数,为其添加
ecr:ListImages、ecr:BatchDeleteImage权限;同时在Lambda资源策略中,允许CodePipeline所在账号的执行角色调用该函数。 - CodePipeline新增执行阶段:在删除CloudFormation栈的阶段之前,添加一个
Invoke类型的Action,调用目标账号的Lambda函数,传入ECR仓库名称参数。 - Lambda核心代码示例:
import boto3 def lambda_handler(event, context): ecr_client = boto3.client('ecr') repo_name = event['Input']['RepoName'] # 批量获取镜像ID img_list_resp = ecr_client.list_images(repositoryName=repo_name) image_ids = [{'imageDigest': img['imageDigest']} for img in img_list_resp.get('imageIds', [])] # 删除所有镜像 if image_ids: ecr_client.batch_delete_image(repositoryName=repo_name, imageIds=image_ids) return {"status": "SUCCEEDED", "message": f"Cleared all images from repo {repo_name}"} - 执行流程:CodePipeline先触发Lambda清理镜像,待镜像清空后,再执行CloudFormation栈删除操作,此时ECR仓库为空,可正常被删除。
方案二:CloudFormation自定义资源钩子(更优雅)
通过自定义资源绑定ECR仓库的生命周期,在栈删除前自动清理镜像:
- 目标账号创建清理Lambda:同方案一,Lambda负责清理指定ECR仓库的所有镜像。
- 修改原CloudFormation模板:添加自定义资源,关联清理Lambda,确保栈删除时先执行镜像清理:
Resources: MyECRRepo: Type: AWS::ECR::Repository Properties: RepositoryName: x DeletionPolicy: Delete ECRImageCleaner: Type: Custom::ECRImageCleaner Properties: ServiceToken: arn:aws:lambda:us-east-1:111199999:function:ECRCleanupFunction RepoName: !Ref MyECRRepo DependsOn: MyECRRepo - 原理:当CloudFormation开始执行栈删除时,会先触发自定义资源对应的Lambda清理镜像,镜像清空后,再删除ECR仓库,避免删除失败。
内容的提问来源于stack exchange,提问作者StrawHat
相关产品推荐
相关产品推荐

