减少 Container Registry 存储

未清理的容器镜像库会随着时间的推移而变大。添加大量镜像或标签时:

  • 获取可用标签或镜像列表变得更慢。
  • 它们占用服务器上大量的存储空间。

我们建议删除不必要的镜像和标签,并设置清理策略,自动管理您的容器镜像库使用情况。

检查 Container Registry 存储使用情况

使用量配额页面(设置 > 使用量配额 > 存储)显示包的存储使用情况,其中不包括 Container Registry。

清理策略

清理策略是一项计划作业,可用于从 Container Registry 中删除标签。 对于定义它的项目,匹配正则表达式 pattern 的标签将被删除。 底层镜像层和镜像保留。

管理员可以使用垃圾收集-m 开关。

启用清理策略

清理策略可以在所有项目上运行,但以下情况除外:

  • 对于自助管理实例,项目必须是在 12.8 或更高版本中创建的。 但是,管理员可以通过设置 container_expiration_policies_enable_historic_entries 为 true,在 GitLab 应用程序设置中为所有项目(甚至是 12.8 之前创建的项目)启用清理策略。 或者,您可以在 Rails 控制台中执行以下命令:

    ApplicationSetting.last.update(container_expiration_policies_enable_historic_entries: true)
    

    如果为所有项目启用,可能存在性能风险,特别是如果您使用外部镜像库。

清理策略工作原理

清理策略会收集 Container Registry 中的所有标签并排除标签,直到只剩下要删除的标签为止。

清理策略根据标签名称搜索镜像。对完整路径的支持尚未实现,但允许您清理动态命名的标签。

清理策略:

  1. 在列表中收集给定仓库的所有标签。
  2. 从列表中排除名为 latest 的标签。
  3. 评估 name_regex(要过期的标签),从列表中排除不匹配的名称。
  4. 从列表中排除任何与 name_regex_keep 值匹配的标签(要保留的标签)。
  5. 排除任何没有 manifest 的标签(不是 UI 中选项的一部分)。
  6. created_date 对剩余标签进行排序。
  7. 根据 keep_n 值(要保留的标签数)从列表中排除 N 个标签。
  8. 从列表中排除比 older_than 值(过期间隔)更新的标签。
  9. 最后,将列表中剩余的标签从 Container Registry 中删除。
caution自助管理实例支持符合 Docker Registry HTTP API V2 规范的第三方容器镜像库。但是,该规范不包括标签删除操作。

创建清理策略

您可以在 API 或 UI 中创建清理策略。

要在 UI 中创建清理策略:

  1. 对于您的项目,转到 设置 > 软件包与镜像库
  2. 展开 清理镜像标签 部分。
  3. 填写字段。

    字段 描述
    切换 打开或关闭策略。
    运行清理 策略应该多久运行一次。
    保留最近的 总是为每个镜像保留多少标签。
    保留匹配标签 确定要保留哪些标签的正则表达式 pattern。latest 标签总是被保留。对于所有标签,使用 .*。请参阅其他 regex pattern 示例
    删除早于以下时间的标签 仅删除早于 X 天的标签。
    删除匹配的标签 确定要删除哪些标签的正则表达式 pattern。该值不能为空。对于所有标签,使用 .*。请参阅其他 regex 模式示例
  4. 点击 保存

根据您选择的时间间隔,策略将被安排运行。

note如果您编辑策略并再次单击 保存,则会重置间隔。

正则表达式 pattern 示例

清理策略使用正则表达式 pattern 来确定应在 UI 和 API 中保留或删除哪些标签。

正则表达式 pattern 会自动用 \A\Z 锚点包围。不要在正则表达式模式中包含任何 \A\Z^$ 标记,因为它们不是必需的。

以下是您可能想要使用的正则表达式 pattern 示例:

  • 匹配所有标签:

    .*
    

    这是到期正则表达式的默认值。

  • 匹配以 v 开头的标签:

    v.+
    
  • 只匹配名为 main 的标签:

    main
    
  • 匹配已命名或以 release 开头的标签:

    release.*
    
  • 匹配以 v 开头、名为 main 或以 release 开头的标签:

    (?:v.+|main|release.*)
    

设置清理限制以节约资源

  • 引入于 13.9 版本。
  • 部署在功能标志后,默认禁用
  • 不推荐用于生产。
  • 要在自助管理实例中使用它,请要求管理员启用

清理策略作为后台进程执行。此过程很复杂,根据要删除的标签数量,该过程可能需要一些时间才能完成。

为了防止服务器资源匮乏,可以使用以下应用程序设置:

  • container_registry_expiration_policies_worker_capacity:同时运行的清理 worker 的最大数量,必须大于或等于 0。我们建议从一个较小的数字开始,并在监控后台 worker 使用的资源后增加它。要删除所有 worker 而不执行清理策略,请将其设置为 0。默认值为4
  • container_registry_delete_tags_service_timeout:清理过程删除一批标签可以花费的最长时间(以秒为单位)。默认值为 250
  • container_registry_cleanup_tags_service_max_list_size:一次执行中可以删除的最大标签数。 必须在另一次执行中删除附加标签。我们建议从一个较小的数字开始,并在监控容器镜像被正确删除后增加它。 默认值为 200
  • container_registry_expiration_policies_caching: 在执行策略期间启用或禁用标签创建时间戳缓存。缓存的时间戳存储在 Redis 中。默认启用。

对于自助管理实例,可以在 Rails 控制台中更新这些设置:

  ApplicationSetting.last.update(container_registry_expiration_policies_worker_capacity: 3)

或者,一旦限制被启用,它们在管理中心可用:

  1. 在顶部栏上,选择 菜单 > 管理员
  2. 进入 设置 > CI/CD > 容器镜像库

使用清理策略 API

您可以使用 GitLab API 设置、更新和禁用清理策略。

示例:

  • 选择所有标签,每个镜像至少保留 1 个标签,清理任何超过 14 天的标签,每月运行一次,保留名称为 main 的所有镜像并启用策略:

    curl --request PUT --header 'Content-Type: application/json;charset=UTF-8' --header "PRIVATE-TOKEN: <your_access_token>" \
         --data-binary '{"container_expiration_policy_attributes":{"cadence":"1month","enabled":true,"keep_n":1,"older_than":"14d","name_regex":"","name_regex_delete":".*","name_regex_keep":".*-main"}}' \
         "https://gitlab.example.com/api/v4/projects/2"
    

使用 API 时 cadence 的有效值为:

  • 1d (每天)
  • 7d (每周)
  • 14d(每两周)
  • 1month(每月)
  • 3month(每季度)

与外部容器镜像库一起使用

使用外部容器镜像库时,在项目上运行清理策略可能会有一些性能风险。 如果一个项目运行一项删除数千个标签的策略,则后台作业可能会被备份或完全失败。 如果您确信要清理的标签数量最少,建议您只为 12.8 之前创建的项目启用容器清理策略。

清理策略故障排查

Something went wrong while updating the cleanup policy.

如果您看到此错误消息,请检查正则表达式 pattern,确保它们有效。

极狐GitLab 在清理策略中使用 RE2 语法 作为正则表达式。您可以使用 regex101 regex tester 测试它们。 查看一些常见的 regex 模式示例

清理策略不删除任何标签

这背后可能有不同的原因:

  • 在 13.6 及更早版本中,当您运行清理策略时,您可能希望它会删除标签,但事实并非如此。当清理策略被保存而不编辑 删除匹配的标签 字段中的值时,就会发生这种情况。该字段有一个灰色的 .* 值作为占位符。除非在字段中明确输入了 .*(或其他正则表达式模式),否则会提交一个 nil 值,此值可防止保存的清理策略匹配任何标签。作为解决方法,请编辑清理策略。在 删除匹配的标签 字段中,输入 .* 并保存,此值表示应删除所有标签。

  • 如果您在自助管理实例上并且容器镜像库中有 1000 多个标签,您可能会遇到 Container Registry 令牌过期问题,并在日志中显示 error authorizing context: invalid token

    要解决此问题,有两种解决方法:

    • 如果您使用的是 13.9 或更高版本,您可以为清理策略设置限制。这样可以及时限制清理执行,并避免过期令牌错误。

    • 延长 Container Registry 身份验证令牌的到期延迟。默认为 5 分钟。您可以通过在 Rails 控制台中运行 ApplicationSetting.last.update(container_registry_token_expire_delay: <integer>) 来设置自定义值,其中 <integer> 是所需的分钟数。请注意,通过扩展此值会增加撤销权限所需的时间。

如果以前的修复不起作用或者您使用的是早期版本,您可以生成要删除的标签列表,然后使用该列表删除标签。请按照下列步骤操作:

  1. 运行以下 shell 脚本。for 循环之前的命令确保在启动循环时始终重新初始化 list_o_tags.out。运行此命令后,所有标签的名称都将在 list_o_tags.out 文件中:

    # Get a list of all tags in a certain container repository while considering [pagination](../../../api/index.md#pagination)
    echo -n "" > list_o_tags.out; for i in {1..N}; do curl --header 'PRIVATE-TOKEN: <PAT>' "https://gitlab.example.com/api/v4/projects/<Project_id>/registry/repositories/<container_repo_id>/tags?per_page=100&page=${i}" | jq '.[].name' | sed 's:^.\(.*\).$:\1:' >> list_o_tags.out; done
    

    如果您有 Rails 控制台访问权限,则可以输入以下命令来检索受日期限制的标签列表:

    output = File.open( "/tmp/list_o_tags.out","w" )
    Project.find(<Project_id>).container_repositories.find(<container_repo_id>).tags.each do |tag|
      output << tag.name + "\n" if tag.created_at < 1.month.ago
    end;nil
    output.close
    

    这组命令创建了一个 /tmp/list_o_tags.out 文件,其中列出了 created_at 日期超过一个月的所有标签。

  2. list_o_tags.out 文件中删除您想要保留的任何标签。以下是一些用于此的示例 sed 命令。请注意,这些命令只是示例。您可以更改它们以适合您的需要:

    # Remove the `latest` tag from the file
    sed -i '/latest/d' list_o_tags.out
    
    # Remove the first N tags from the file
    sed -i '1,Nd' list_o_tags.out
    
    # Remove the tags starting with `Av` from the file
    sed -i '/^Av/d' list_o_tags.out
    
    # Remove the tags ending with `_v3` from the file
    sed -i '/_v3$/d' list_o_tags.out
    

    如果您运行的是 macOS,则必须将 .back 添加到命令中。 例如:

    sed -i .bak '/latest/d' list_o_tags.out
    
  3. 仔细检查 list_o_tags.out 文件以确保它只包含您要删除的标签。

  4. 运行此 shell 脚本,删除 list_o_tags.out 文件中的标签:

    # loop over list_o_tags.out to delete a single tag at a time
    while read -r LINE || [[ -n $LINE ]]; do echo ${LINE}; curl --request DELETE --header 'PRIVATE-TOKEN: <PAT>' "https://gitlab.example.com/api/v4/projects/<Project_id>/registry/repositories/<container_repo_id>/tags/${LINE}"; sleep 0.1; echo; done < list_o_tags.out > delete.logs