{{< details >}}

  • Tier: 基础版, 专业版, 旗舰版
  • Offering: JihuLab.com, 私有化部署

{{< /details >}}

如果您不管理仓库的使用,容器镜像仓库可能会随着时间的推移而增大。例如,如果您添加了大量的镜像或标签:

  • 检索可用标签或镜像列表会变慢。
  • 它们会占用服务器上的大量存储空间。

您应该删除不必要的镜像和标签,并设置一个容器镜像仓库清理策略,以自动管理您的容器镜像仓库使用情况。

查看容器镜像仓库的使用情况

{{< details >}}

  • Tier: 基础版, 专业版, 旗舰版

{{< /details >}}

{{< history >}}

  • 引入于极狐GitLab 15.7。

{{< /history >}}

查看您的容器镜像仓库存储库的存储使用数据。

对于一个项目

先决条件:

要查看项目的存储使用情况:

  1. 在左侧边栏,选择 搜索或前往 并找到您的项目。
  2. 执行以下操作之一:
    • 要查看总存储使用情况,选择 设置 > 使用配额。在 命名空间实体 下,选择 容器镜像仓库 以查看单个存储库。
    • 要直接查看存储库的存储使用情况,选择 部署 > 容器镜像仓库

您还可以使用:

  • 项目 API 获取项目的总容器镜像仓库存储。
  • 仓库 API 获取特定存储库的大小数据。

对于一个群组

先决条件:

要查看群组的存储使用情况:

  1. 在左侧边栏,选择 搜索或前往 并找到您的群组。
  2. 选择 设置 > 使用配额
  3. 选择 存储 选项卡。

您还可以使用 群组 API 获取群组中所有项目的总容器镜像仓库存储。

存储数据更新

在启用元数据数据库后:

  • 对于新的容器镜像,大小数据在推送后立即可用。
  • 对于现有的容器镜像,大小数据在后台计算,可能需要长达 24 小时。

存储数据更新发生在:

  • 当您推送或删除容器镜像时立即更新。
  • 实时更新时,您可以:
  • 当您在项目的容器存储库中推送或删除标签时。
  • 每 5 分钟更新一次群组。

{{< alert type=”note” >}}

对于极狐GitLab私有化部署实例,当管理员启用元数据数据库后,存储数据变得可用。在 JihuLab.com 上,元数据数据库默认启用。

{{< /alert >}}

如何计算容器镜像仓库的使用情况

存储在容器镜像仓库中的镜像层在根命名空间级别进行去重。

如果以下情况之一发生,镜像只会计算一次:

  • 您在同一存储库中多次标记相同的镜像。
  • 您在同一个根命名空间下的不同存储库中标记相同的镜像。

如果以下情况之一发生,镜像层只会计算一次:

  • 您在同一个容器存储库、项目或群组中共享镜像层。
  • 您在不同的存储库中共享镜像层。

只有被标记的镜像引用的层才会被计算在内。未标记的镜像和任何仅由它们引用的层会被在线垃圾回收。如果在此期间未被引用,未标记的镜像层将在 24 小时后自动删除。

镜像层以原始(通常是压缩的)格式存储在存储后端。这意味着任何给定镜像层的测量大小应与相应的镜像清单上显示的大小匹配。

命名空间使用在标签从命名空间下的任何容器存储库中推送或删除后几分钟刷新一次。

延迟刷新

对于极大的命名空间(约占命名空间的 1%),无法实时计算容器镜像仓库使用情况以达到最大精度。为了使这些命名空间的维护者能够看到其使用情况,存在一种延迟回退机制。

如果无法精确计算命名空间的使用情况,极狐GitLab会回退到延迟方法。在延迟方法中,显示的使用大小是命名空间中所有唯一镜像层的总和。未标记的镜像层不会被忽略。因此,在删除标签后,显示的使用大小可能不会显著变化。相反,只有在以下情况时,大小值才会改变:

  • 自动垃圾回收过程运行并删除未标记的镜像层。用户删除标签后,垃圾回收运行被安排在 24 小时后开始。在该运行期间,之前标记的镜像将被分析,如果没有被其他标记镜像引用,其层将被删除。如果删除了任何层,则会更新命名空间使用情况。
  • 命名空间的仓库使用量减少到极狐GitLab可以精确测量的程度。随着命名空间使用量的减少,测量会自动从延迟测量切换到精确使用测量。

清理策略

{{< history >}}

  • 在极狐GitLab 15.0 中,所需权限从开发者更改为维护者。

{{< /history >}}

清理策略是一个计划任务,您可以用它从容器镜像仓库中删除标签。对于定义它的项目,匹配正则表达式模式的标签将被移除。底层的层和镜像保持不变。

要删除与任何标签无关的底层层和镜像,管理员可以使用垃圾回收以及 -m 开关。

启用清理策略

{{< alert type=”warning” >}}

出于性能原因,对于 JihuLab.com 上没有容器镜像的项目,启用的清理策略会自动禁用。

{{< /alert >}}

清理策略如何工作

清理策略收集容器镜像仓库中的所有标签,并排除一些标签,直到只剩下您想删除的标签。

清理策略根据标签名称搜索镜像。

清理策略:

  1. 将给定存储库的所有标签收集到一个列表中。
  2. 排除名为 latest 的标签。
  3. 评估 name_regex(要过期的标签),排除不匹配的名称。
  4. 排除任何与 name_regex_keep 值(要保留的标签)匹配的标签。
  5. 排除任何没有清单的标签(不在 UI 的选项中)。
  6. created_date 排序剩余的标签。
  7. 根据 keep_n 值(要保留的标签数量)排除 N 个标签。
  8. 排除早于 older_than 值(过期间隔)的标签。
  9. 排除受保护的标签
  10. 从容器镜像仓库中删除列表中的剩余标签。

{{< alert type=”warning” >}}

在 JihuLab.com 上,清理策略的执行时间是有限的。策略运行后,某些标签可能仍留在容器镜像仓库中。下次策略运行时,剩余的标签将被包括在内。可能需要多次运行才能删除所有标签。

{{< /alert >}}

{{< alert type=”warning” >}}

极狐GitLab私有化部署实例支持符合 Docker Registry HTTP API V2 规范的第三方容器镜像仓库。然而,该规范不包括标签删除操作。因此,当与第三方容器镜像仓库交互时,极狐GitLab使用了一种变通方法来删除标签。由于可能的实现差异,这种变通方法不能保证在所有第三方仓库中以相同的可预测方式工作。如果您使用极狐GitLab容器镜像仓库,则不需要这种变通方法,因为我们实现了一个特殊的标签删除操作。在这种情况下,您可以期望清理策略是一致且可预测的。

{{< /alert >}}

示例清理策略工作流程

清理策略的保留和删除规则之间的交互可能很复杂。例如,对于具有以下清理策略配置的项目:

  • 保留最新:每个镜像名称 1 个标签。
  • 保留匹配的标签production-.*
  • 删除早于:7 天的标签。
  • 删除匹配的标签.*

以及具有以下标签的容器存储库:

  • latest,2 小时前发布。
  • production-v44,3 天前发布。
  • production-v43,6 天前发布。
  • production-v42,11 天前发布。
  • dev-v44,2 天前发布。
  • dev-v43,5 天前发布。
  • dev-v42,10 天前发布。
  • v44,昨天发布。
  • v43,12 天前发布。
  • v42,20 天前发布。

在此示例中,下次清理运行中将删除的标签是 dev-v42v43v42。您可以将规则解释为按以下优先级应用:

  1. 保留规则具有最高优先级。标签必须在匹配任何规则时保留。
    • latest 标签必须保留,因为 latest 标签总是保留。
    • production-v44production-v43production-v42 标签必须保留,因为它们匹配保留匹配的标签规则。
    • v44 标签必须保留,因为它是最新的,匹配保留最新规则。
  2. 删除规则具有较低优先级,只有在所有规则匹配时才删除标签。对于不匹配任何保留规则的标签(dev-44dev-v43dev-v42v43v42):
    • dev-44dev-43 匹配删除早于规则,并被保留。
    • dev-v42v43v42 匹配删除早于删除匹配的标签规则,因此这三个标签可以删除。

创建清理策略

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

要在 UI 中创建清理策略:

  1. 在左侧边栏,选择 搜索或前往 并找到您的项目。
  2. 选择 设置 > 软件包和仓库
  3. 展开 容器镜像仓库
  4. 容器镜像仓库清理策略 下,选择 设置清理规则
  5. 完成字段:

    字段 描述
    切换 打开或关闭策略。
    运行清理 策略应运行的频率。
    保留最新 每个镜像名称_始终_保留的标签数。
    保留匹配的标签 确定要保留的标签的正则表达式模式。latest 标签始终保留。对于所有标签,使用 .*。参见其他正则表达式模式示例
    删除早于 仅删除早于 X 天的标签。
    删除匹配的标签 确定要删除的标签的正则表达式模式。此值不能为空。对于所有标签,使用 .*。参见其他正则表达式模式示例

    {{< alert type=”note” >}}

    保留和删除正则表达式模式都会自动围绕着 \A\Z 锚点,因此您不需要包括它们。然而,在选择和测试正则表达式模式时,请务必考虑到这一点。

    {{< /alert >}}

  6. 选择 保存

策略将在您选择的计划间隔运行。

{{< alert type=”note” >}}

如果您编辑策略并再次选择 保存,间隔会被重置。

{{< /alert >}}

正则表达式模式示例

清理策略使用正则表达式模式来确定哪些标签应保留或删除,无论是在 UI 还是 API 中。

极狐GitLab在清理策略中使用 RE2 语法进行正则表达式。

以下是您可以使用的一些正则表达式模式示例:

  • 匹配所有标签:

    .*
    

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

  • 匹配以 v 开头的标签:

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

    main
    
  • 匹配名称为或以 release 开头的标签:

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

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

设置清理限制以节省资源

{{< history >}}

  • 在极狐GitLab 15.0 中,移除了 container_registry_expiration_policies_throttling 功能标志。

{{< /history >}}

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

您可以使用以下应用程序设置来防止服务器资源枯竭:

  • container_registry_expiration_policies_worker_capacity: 并行运行的最大清理工作线程数。此值必须大于或等于 0。您应该从较低的数字开始,并在监视后台工作线程使用的资源后增加它。要删除所有工作线程并不执行清理策略,将此设置为 0。默认值是 4
  • container_registry_delete_tags_service_timeout: 清理过程删除一批标签所需的最大时间(以秒为单位)。默认值是 250
  • container_registry_cleanup_tags_service_max_list_size: 单次执行中可以删除的最大标签数量。附加标签必须在另一次执行中删除。您应该从较低的数字开始,并在确认容器镜像已正确删除后增加它。默认值是 200
  • container_registry_expiration_policies_caching: 在策略执行期间启用或禁用标签创建时间戳缓存。缓存的时间戳存储在 Redis 中。默认启用。

对于极狐GitLab私有化部署实例,可以在 Rails 控制台 中更新这些设置:

ApplicationSetting.last.update(container_registry_expiration_policies_worker_capacity: 3)

它们也可在 管理员 区域中找到:

  1. 在左侧边栏,底部选择 管理员
  2. 选择 设置 > CI/CD
  3. 展开 容器镜像仓库

使用清理策略 API

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

示例:

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

    curl --fail-with-body --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_keep":".*-main"}}' \
         "https://gitlab.example.com/api/v4/projects/2"
    

在使用 API 时,cadence 的有效值为:

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

在使用 API 时,keep_n(每个镜像名称保留的标签数量)的有效值为:

  • 1
  • 5
  • 10
  • 25
  • 50
  • 100

在使用 API 时,older_than(标签自动删除的天数)的有效值为:

  • 7d
  • 14d
  • 30d
  • 90d

有关更多详细信息,请参阅 API 文档:编辑项目 API

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

当使用外部容器镜像仓库时,在项目上运行清理策略可能会有一些性能风险。如果一个项目运行策略以删除数千个标签,极狐GitLab后台作业可能会积压或完全失败。

更多容器镜像仓库存储减少选项

以下是一些其他选项,您可以用来减少项目所用的容器镜像仓库存储:

故障排除

存储大小不可用

如果您无法查看容器镜像仓库存储大小信息:

  1. 请管理员验证元数据数据库是否已正确配置
  2. 验证仓库存储后端是否正确配置并可访问。
  3. 检查仓库日志中的存储相关错误:

    sudo gitlab-ctl tail registry
    

更新清理策略时出了点问题。

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

您可以使用 regex101 正则表达式测试器使用 Golang 风格测试它们。查看一些常见的正则表达式模式示例

清理策略不删除任何标签

这可能有不同的原因:

  • 如果您使用极狐GitLab私有化部署,并且在容器存储库中有 1000 多个标签,您可能会遇到一个容器镜像仓库令牌过期问题,日志中显示 error authorizing context: invalid token

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

或者,您可以生成要删除的标签列表,并使用该列表删除标签。要创建列表并删除标签:

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

    # 获取某个容器存储库中所有标签的列表,同时考虑[分页](../../../api/rest/_index.md#pagination)
    echo -n "" > list_o_tags.out; for i in {1..N}; do curl --fail-with-body --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 文件,列出所有创建日期超过一个月的标签。

  2. list_o_tags.out 文件中删除您想要保留的任何标签。例如,您可以使用 sed 来解析文件并删除标签。

    {{< tabs >}}

    {{< tab title=”Linux” >}}

    # 从文件中删除 `latest` 标签
    sed -i '/latest/d' list_o_tags.out
    
    # 从文件中删除前 N 个标签
    sed -i '1,Nd' list_o_tags.out
    
    # 从文件中删除以 `Av` 开头的标签
    sed -i '/^Av/d' list_o_tags.out
    
    # 从文件中删除以 `_v3` 结尾的标签
    sed -i '/_v3$/d' list_o_tags.out
    

    {{< /tab >}}

    {{< tab title=”macOS” >}}

    # 从文件中删除 `latest` 标签
    sed -i .bak '/latest/d' list_o_tags.out
    
    # 从文件中删除前 N 个标签
    sed -i .bak '1,Nd' list_o_tags.out
    
    # 从文件中删除以 `Av` 开头的标签
    sed -i .bak '/^Av/d' list_o_tags.out
    
    # 从文件中删除以 `_v3` 结尾的标签
    sed -i .bak '/_v3$/d' list_o_tags.out
    

    {{< /tab >}}

    {{< /tabs >}}

  3. 仔细检查 list_o_tags.out 文件,以确保它只包含您想要删除的标签。

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

    # 循环遍历 list_o_tags.out 文件,一次删除一个标签
    while read -r LINE || [[ -n $LINE ]]; do echo ${LINE}; curl --fail-with-body --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