如何使用 CloudFormation 强制删除 AWS ECR?

Mar*_*son 7 amazon-web-services amazon-ecs aws-cloudformation

使用 CloudFormation 删除包含带有图像的 ECR 的堆栈会导致失败消息:

The repository with name 'my-repo' in registry with id '123' cannot be deleted because it still contains images
Run Code Online (Sandbox Code Playgroud)

CLI 提供了一种通过使用--force标志来覆盖它的方法:

aws ecr delete-repository --repository-name my-repo --force
Run Code Online (Sandbox Code Playgroud)

如何仅使用 CloudFormation 获得相同的结果?

Unb*_*ess 0

当前无法强制删除 ECR 存储库。事实上,有一个未解决的问题需要此功能。

作为解决方法,您可以部署lambda 支持的自定义资源,该资源在堆栈删除时清空 ECR 存储库。

当您将 Lambda 函数与自定义资源关联时,每当创建、更新或删除自定义资源时都会调用该函数。AWS CloudFormation 调用 Lambda API 来调用该函数并将所有请求数据(例如请求类型和资源属性)传递给该函数。

这是一个最小的可重现示例:

{
    "Parameters": {
        "ECRRepositoryName": {
            "Description": "Name of ECR repository",
            "Default": "test-repository",
            "Type": "String"
        }
    },
    "Resources": {
        "ECRRepository": {
            "Type": "AWS::ECR::Repository",
            "Properties": {
                "RepositoryName": {
                    "Ref": "ECRRepositoryName"
                }
            }
        },
        "LambdaEmptyECRRole": {
            "Type": "AWS::IAM::Role",
            "Properties": {
                "AssumeRolePolicyDocument": {
                    "Version": "2012-10-17",
                    "Statement": [
                        {
                            "Effect": "Allow",
                            "Principal": {
                                "Service": "lambda.amazonaws.com"
                            },
                            "Action": "sts:AssumeRole"
                        }
                    ]
                },
                "Path": "/",
                "Policies": [
                    {
                        "PolicyName": "ecr-access-policy",
                        "PolicyDocument": {
                            "Version": "2012-10-17",
                            "Statement": [
                                {
                                    "Effect": "Allow",
                                    "Action": [
                                        "ecr:*"
                                    ],
                                    "Resource": "*"
                                }
                            ]
                        }
                    }
                ]
            }
        },
        "LambdaEmptyECR": {
            "Type": "AWS::Lambda::Function",
            "DependsOn": "ECRRepository",
            "Properties": {
                "Code": {
                    "ZipFile": {
                        "Fn::Join": [
                            "\n",
                            [
                                "import os",
                                "import cfnresponse",
                                "import boto3",
                                "",
                                "def lambda_handler(event, context):",
                                "    response = {}",
                                "    if event['RequestType'] == 'Delete':",
                                "        region = event['ResourceProperties']['Region']",
                                "        repository_name = event['ResourceProperties']['ECRRepositoryName']",
                                "        client = boto3.client('ecr', region_name=region)",
                                "        images = client.list_images(repositoryName=repository_name)",
                                "        image_ids = [image for image in images['imageIds']]",
                                "        try:",
                                "            client.batch_delete_image(repositoryName=repository_name, imageIds=image_ids)",
                                "            while client.list_images(repositoryName=repository_name)['imageIds'] != []:",
                                "                os.sleep(1) # wait for images to be deleted",
                                "            response['output'] = 'Successfully deleted images in ECR repository'",
                                "            cfnresponse.send(event, context, cfnresponse.SUCCESS, response)",
                                "        except Exception as e:",
                                "            response['output'] = 'Error'+ e.__str__()",
                                "            cfnresponse.send(event, context, cfnresponse.FAILED, response)",
                                "    cfnresponse.send(event, context, cfnresponse.SUCCESS, response)"
                            ]
                        ]
                    }
                },
                "Handler": "index.lambda_handler",
                "Role": {
                    "Fn::GetAtt": [
                        "LambdaEmptyECRRole",
                        "Arn"
                    ]
                },
                "Runtime": "python3.8"
            }
        },
        "EmptyECR": {
            "Type": "Custom::LambdaDependency",
            "DependsOn": "ECRRepository",
            "Properties": {
                "ServiceToken": {
                    "Fn::GetAtt": [
                        "LambdaEmptyECR",
                        "Arn"
                    ]
                },
                "ECRRepositoryName": {
                    "Ref": "ECRRepositoryName"
                },
                "Region": {
                    "Ref": "AWS::Region"
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在堆栈删除时,会在删除 ECR 存储库之前调用 lambda 函数,并删除存储库中包含的所有图像。

有关自定义资源的更多信息:https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources.html


要尝试这个示例:

  1. 部署 CloudFormation 模板
  2. 将任何镜像推送到 ECR 存储库
  3. 删除 CloudFormation 模板