Help us learn about your current experience with the documentation. Take the survey.

减少容器注册表存储

  • Tier: Free, Premium, Ultimate
  • Offering: GitLab.com, GitLab Self-Managed, GitLab Dedicated

如果不管理注册表使用情况,容器注册表的大小可能会随时间增长。例如,如果您添加大量镜像或标签:

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

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

查看容器注册表使用情况

  • Tier: Free, Premium, Ultimate

查看容器注册表仓库的存储使用数据。

对于项目

先决条件:

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

  1. 在左侧边栏,选择 Search or go to 并找到您的项目。
  2. 执行以下操作之一:
    • 要查看总存储使用情况,选择 Settings > Usage quotas。 在 Namespace entities 下,选择 Container Registry 查看各个仓库。
    • 要直接按仓库查看存储使用情况,选择 Deploy > Container Registry

您还可以使用:

对于群组

先决条件:

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

  1. 在左侧边栏,选择 Search or go to 并找到您的群组。
  2. 选择 Settings > Usage quotas
  3. 选择 Storage 选项卡。

您还可以使用 Groups API 获取群组中所有项目的总容器注册表存储。

存储数据更新

启用元数据库后:

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

存储数据更新发生在:

  • 推送或删除容器镜像时立即更新。
  • 当您执行以下操作时实时更新:
  • 在项目的容器仓库中推送或删除标签时。
  • 群组每 5 分钟更新一次。

对于 GitLab 自托管实例,存储数据在管理员启用元数据库后立即可用。 在 GitLab.com 上,元数据库默认启用。

容器注册表使用情况如何计算

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

如果满足以下条件,镜像只计算一次:

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

如果满足以下条件,镜像层只计算一次:

  • 您在同一容器仓库、项目或群组中的多个镜像之间共享该镜像层。
  • 您在不同仓库之间共享该镜像层。

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

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

命名空间使用情况在从命名空间下的任何容器仓库推送或删除标签后几分钟内刷新。

延迟刷新

对于非常大的命名空间(约占命名空间的 1%),无法实时以最大精度计算容器注册表使用情况。为了使这些命名空间的维护者能够查看其使用情况,有一个延迟回退机制。有关更多详细信息,请参阅 epic 9413

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

  • 自动垃圾回收过程运行并删除未标记的镜像层。用户删除标签后,垃圾回收运行计划在 24 小时后开始。在此运行期间,先前标记的镜像会被分析,如果未被任何其他标记镜像引用,则删除其层。如果删除了任何层,命名空间使用情况会更新。
  • 命名空间的注册表使用量减少到 GitLab 可以以最大精度测量的程度。随着命名空间使用量的减少,测量会自动从延迟切换到精确使用测量。在 UI 中没有地方可以确定使用的是哪种测量方法,但 issue 386468 提议改进这一点。

清理策略

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

要删除与任何标签都不关联的底层层和镜像,管理员可以使用带有 -m 开关的垃圾回收

启用清理策略

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

清理策略如何工作

清理策略收集容器注册表中的所有标签,并排除标签,直到只剩下您想要删除的标签。

清理策略根据标签名称搜索镜像。完整路径匹配的支持在问题 281071 中跟踪。

清理策略:

  1. 收集给定仓库中的所有标签到列表中。
  2. 排除名为 latest 的标签。
  3. 评估 name_regex(要过期的标签),排除不匹配的名称。
  4. 排除与 name_regex_keep 值匹配的任何标签(要保留的标签)。
  5. 排除任何没有清单的标签(不是 UI 中的选项)。
  6. created_date 对剩余标签进行排序。
  7. 根据 keep_n 值排除 N 个标签(要保留的标签数量)。
  8. 排除比 older_than 值更新的标签(过期间隔)。
  9. 排除受保护的标签
  10. 排除不可变标签
  11. 从容器注册表中删除列表中剩余的标签。

在 GitLab.com 上,清理策略的执行时间有限。策略运行后,某些标签可能仍保留在容器注册表中。下次策略运行时,剩余的标签会被包含。可能需要多次运行才能删除所有标签。

GitLab 自托管实例支持符合 Docker Registry HTTP API V2 规范的第三方容器注册表。但是,该规范不包括标签删除操作。因此,GitLab 在与第三方容器注册表交互时使用变通方法来删除标签。有关更多信息,请参阅问题 15737。由于可能的实现差异,此变通方法不能保证以相同可预测的方式与所有第三方注册表一起工作。如果您使用 GitLab 容器注册表,则不需要此变通方法,因为我们实现了特殊的标签删除操作。在这种情况下,您可以期望清理策略是一致和可预测的。

清理策略工作流示例

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

  • 保留最新的:每个镜像名称保留 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. 在左侧边栏,选择 Search or go to 并找到您的项目。

  2. 选择 Settings > Packages and registries

  3. 展开 Container registry

  4. Container registry cleanup policies 下,选择 Set cleanup rules

  5. 完成以下字段:

    字段 描述
    Toggle 开启或关闭策略。
    Run cleanup 策略应运行的频率。
    Keep the most recent 为每个镜像始终保留的标签数量。
    Keep tags matching 确定要保留哪些标签的正则表达式模式。latest 标签始终保留。要保留所有标签,使用 .*。请参阅其他正则表达式模式示例
    Remove tags older than 仅删除早于 X 天的标签。
    Remove tags matching 确定要删除哪些标签的正则表达式模式。此值不能为空。要删除所有标签,使用 .*。请参阅其他正则表达式模式示例

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

  6. 选择 Save

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

如果您编辑策略并再次选择 Save,间隔将重置。

正则表达式模式示例

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

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

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

  • 匹配所有标签:

    .*

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

  • 匹配以 v 开头的标签:

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

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

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

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

设置清理限制以节省资源

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

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

  • 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)

它们也可在 Admin 区域 中使用:

  1. 在左侧边栏底部,选择 Admin
  2. 选择 Settings > CI/CD
  3. 展开 Container Registry

使用清理策略 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 文档:Edit project API

与外部容器注册表一起使用

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

更多容器注册表存储减少选项

以下是一些可以用来减少项目使用的容器注册表存储的其他选项:

故障排除

存储大小不可用

如果您看不到容器注册表存储大小信息:

  1. 要求管理员验证元数据库已正确配置

  2. 验证注册表存储后端是否正确配置且可访问。

  3. 检查注册表日志中的存储相关错误:

    sudo gitlab-ctl tail registry

更新清理策略时出现错误。

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

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

清理策略不删除任何标签

这可能有不同的原因:

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

  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:^.\(.*\).$::' >> 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 解析文件并删除标签。

    # 从文件中删除 `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
    # 从文件中删除 `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
  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