如何删除 AWS ECR 未标记和较旧的图像?

亚马逊 ECR 镜像管理: 保持容器仓库整洁

亚马逊 ECR(Elastic Container Registry)与 Amazon EKS(Elastic Kubernetes Service)、Amazon ECS(Elastic Container Service)和 AWS Lambda 紧密集成,简化了从开发到生产的整个流程。借助亚马逊 ECR,您可以将容器镜像托管在高度可扩展且高可用的架构中,确保您的应用程序可以可靠部署。为了维持良好的环境,定期删除未标记和旧的镜像至关重要。

如今,应用程序通常以微服务的形式运行。 微服务本质上是容器,它封装了所有代码及其依赖项,使得应用程序可以在任何计算环境中快速可靠地运行。 容器因其便携性、小巧的尺寸和便利性而成为现代应用程序的首选运输方式。

容器是基于称为镜像的只读模板构建的。 这些镜像需要存储在某个地方,以便任何有权访问的机器可以检索它们。 这就是容器注册表的作用。以前,人们通常使用 DockerHub 来存储这些镜像和工件。 然而,如果您正在使用 AWS 云服务,那么 AWS ECR(作为 DockerHub 的替代方案)很可能是您的选择。

AWS ECR 是一种完全托管的容器注册表,提供高性能的托管服务,允许您以公共和私有存储库的形式部署应用程序镜像和工件。 每天,无数的 AWS 托管应用程序将数百万个镜像/应用程序工件推送到或拉取到特定的 ECR 存储库中。

在本文中,我们将探讨如何清理 AWS ECR 中过时和旧的镜像,从而保持您的 ECR 存储库的整洁。

立即删除未标记和旧的镜像的需求

清理 ECR 存储库的主要原因是为了保持良好的开发卫生。 通常,没有人希望自己的 ECR 中保存超过 10 个已部署的镜像。 行业中经常会发生回滚操作,但很少需要从之前的 5 个工件还原变更。

简单来说,任何超过 5 次部署的镜像/工件都可能不再需要。 虽然组织策略可能有所不同,但通常建议将其作为最佳实践。在业界,通常会标记最新或最后 5 个最稳定的镜像。 软件开发生命周期中会快速生成新镜像,旧的镜像则会被新的镜像替代,导致旧镜像没有标记且不再有用。

此外,镜像/工件通常体积较大,会增加 ECR 的存储成本。 AWS ECR 的定价是“存储在私有或公共存储库中的数据每 GB/月 0.10 美元”。 这个价格可能看起来很小,但就像人们常说的那样,积少成多。 长期存放这些镜像可能会导致您的 AWS 账单金额增加。

强烈建议清理 ECR 存储库中这些旧的和未标记的镜像,因为它们不再有用。 为什么要保留它们并支付额外的费用?

手动删除 AWS ECR 镜像

方法 1:通过 GUI 删除

步骤 1: 登录到您的 Amazon Web Services 帐户,并导航到您想要清理的存储库。

步骤 2: 在这里,您可以看到存储库中的最新标签,这些标签表示最稳定的版本。 您看到的其他标签可能被认为是未标记的。要删除,您只需选择图像并单击删除即可。

步骤 3:确认删除。

方法 2:通过 CLI 删除

要使用 CLI 删除镜像,您需要在计算机上配置所有 AWS IAM 访问密钥以及授予您访问存储库所需 IAM 权限。 在这里,我们假设您已经完成了配置。 如果您尚未配置,请参考 AWS 配置基础指南进行配置。

如果您不确定是否已在计算机上配置 AWS CLI,请使用以下命令验证:

aws sts get-caller-identity

现在您已经确认可以使用 AWS CLI,您可以使用以下命令删除未标记的 ECR 镜像:

aws ecr batch-delete-image --repository-name test-ecr-policy --image-ids imageTag=custom-image-6

这里我们所做的与在 GUI 中所做的类似。 我们正在删除存储库 test-ecr-policy 中标记为 custom-image-6 的镜像。

方法 3:通过脚本删除

此方法的前提条件是在您运行脚本的机器上配置了 AWS 访问密钥。

这是用于删除未标记镜像的脚本:

import boto3

client = boto3.client('ecr')

response = client.list_images(repositoryName="test-ecr-policy")

untaggedImageList = [image for image in response['imageIds'] if image['imageTag'] == 'custom-build-4']

response2 = client.batch_delete_image(repositoryName="aws-test-ecrpolicy", imageIds=untaggedImageList)

print(response2)
  

响应将返回已删除的镜像 ID 列表以及任何失败信息。

定期删除 ECR 镜像

如果您是一名 DevOps 工程师或经常管理 AWS ECR,您一定深知手动删除这些镜像的痛苦。 虽然运行脚本/命令可以使工作变得更容易,但您肯定希望找到一种可以自动删除这些镜像的方法,而无需担心。 好消息是,AWS ECR 为您的镜像提供了生命周期策略,您可以设置策略来定时或按计划删除镜像。 让我们来看看具体如何操作。

方法 1:通过 GUI 配置生命周期策略

步骤 1:导航到您要设置生命周期策略的存储库。 在左侧面板中,您可以看到“生命周期策略”选项。 点击开始。

步骤 2:单击它并创建您的第一条规则。

步骤 3:ECR 允许您在两种情况下删除镜像。 一种是当镜像超过指定天数,另一种是当镜像被标记/未标记且您只想保留它们,例如 X 天。

让我们看看如何配置。 您可以设置是否要删除未标记的镜像,是否为 1 天或更早的镜像,或者未标记镜像的镜像计数是否超过一个。 根据您的用例进行选择。 不要忘记,您可以将这些数字增加到您选择的数值。 保存更改以应用生命周期规则。

方法 2:通过 CLI 配置生命周期策略

用于设置生命周期策略的 AWS ECR CLI 命令是 put-lifecycle-policy。让我们看看如何操作。为此,您需要创建一个 JSON 文件,列出策略的条件。 您可以将此文件命名为 policy.json 或任何您选择的名称。

在开始之前,让我们先回顾一下生命周期策略的组成元素:

rulePriority (类型:整数,必选:是):

规则的执行顺序,由低到高。 具有优先级 1 的生命周期策略规则将首先应用,然后是 2,依此类推。 生命周期策略规则必须具有唯一的优先级值。 策略规则不需要连续值。“Any-tagged”规则必须具有最高的 rulePriority,并且最后被检查。

description (类型:字符串,必选:否):

描述生命周期策略中规则的用途。

tagStatus (类型:字符串,必选:是):

检查添加的生命周期策略规则是否指定了镜像标签。 可选值为“标记”、“未标记”或“任何”。 如果未指定,则评估所有镜像。 “标记”需要一个 tagPrefixList 值。“未标记”需要省略 tagPrefixList

tagPrefixList (类型:字符串列表,必选:是,仅当 tagStatus 设置为标记时):

如果“tagStatus”为“标记”,则您的生命周期策略需要以逗号分隔的镜像标签前缀列表。

使用标签前缀“prod”,您可以指定标记为“prod”、“prod1”、“prod2”等的所有镜像。 多标签只会选择包含所有标签的镜像。

countType (类型:字符串,必选:是):

如果 countTypeimageCountMoreThan,则指定 countNumber 以限制存储库中的镜像数量。

如果 countTypesinceImagePushed,则指定 countUnitcountNumber 以限制存储库的镜像。

countUnit (类型:字符串,必选:是,仅当 countType 设置为 sinceImagePushed 时):

仅当 countTypesinceImagePushed 时才指定计数单位;否则,会发生错误。

countNumber (类型:整数,必选:是):

仅限正整数(0 不是可接受的值)。 如果 countTypeimageCountMoreThan,则此值是要保留的最大镜像数。 使用 sinceImagePushed 作为 countType 可确定最大镜像年龄。

type (类型:字符串,必选:是):

选择一种操作类型。 可接受的值是“过期”。

这是我的 policy.json 文件内容:

{
  "rules": [
    {
      "rulePriority": 1,
      "description": "Expire images older than 10 days",
      "selection": {
        "tagStatus": "untagged",
        "countType": "sinceImagePushed",
        "countUnit": "days",
        "countNumber": 14
      },
      "action": {
        "type": "expire"
      }
    }
  ]
}
  

您可以根据贵组织的要求自定义此策略。“sinceImagePushed”可以替换为“imageCountMoreThan”。

用于设置此策略的 CLI 命令为:

aws ecr put-lifecycle-policy --repository-name "test-ecr-polict" --lifecycle-policy-text "file://policy.json"

方法 3:通过脚本配置生命周期策略

我们将使用 boto3 命令来实现此目的。 我们可以使用相同的 policy.json 文件。 以下是示例代码片段:

import boto3

client = boto3.client('ecr')

response = client.put_lifecycle_policy(
  registryId='PODES12342',
  repositoryName="test-ecr-policy",
  lifecyclePolicyText="plicy.json"
)

print(response)

如何跨多个 ECR 存储库应用单个策略?

经常会遇到如何跨多个存储库应用相同策略的问题。

手动设置策略是一项重复且枯燥的任务。

以下是一个可用于生产系统的代码片段,可以跨 100 多个存储库应用策略:

from boto3 import Session,client
from os import getenv

AWS_ACCESS_KEY_ID = getenv("ACCESSKEY")
AWS_SECRET_ACCESS_KEY = getenv("SECRETKEY")

session = Session(
  aws_access_key_id=AWS_ACCESS_KEY_ID,
  aws_secret_access_key=AWS_SECRET_ACCESS_KEY
)
client = client('ecr')
response = client.describe_repositories()
repositories = response['repositories']
globalLifecyclePolicy = 'put your policy here’
for repo in repositories:
  repoName = repo['repositoryName']
  client.put_lifecycle_policy( repositoryName = repoName,lifecyclePolicyText = globalLifecyclePolicy)

结论

我们可以根据指定的参数轻松构建 ECR 生命周期策略并清理旧镜像。 AWS 提供了大量的文档和生命周期策略示例供您参考。您还可以针对标记的镜像尝试替代策略,例如将条件与镜像上传日期匹配。 此外,您还可以探索一些 AWS 的关键术语,这将有助于您学习 AWS。