Optimizing GitLab for large repositories

Optimizing GitLab for large repositories

通常,由于克隆和签出所需的时间,在工作树中包含超过 5 万个文件的大型存储库通常需要特别考虑.

GitLab 和 GitLab Runner 可以很好地处理这种情况,但是需要优化的配置才能有效地执行其操作.

处理大型存储库的一般准则很简单. 以下各节将更详细地描述每个准则:

  • 始终以增量方式获取. 请勿以导致重新创建所有工作树的方式进行克隆.
  • 始终使用浅克隆来减少数据传输. 请注意,由于 CPU 影响更大,这给 GitLab 实例带来了更多负担.
  • 如果您大量使用基于 fork 的工作流,请控制克隆目录.
  • 优化git clean标志,以确保删除或保留可能影响或加快构建速度的数据.

在 GitLab Runner 8.9 中引入.

默认情况下,GitLab 和 GitLab Runner 始终执行完整克隆. 虽然这意味着已收到来自 GitLab 的所有更改,但通常会导致接收额外的提交日志.

理想情况下,您应始终使用GIT_DEPTH ,该数字应较小,例如 10.这将指示 GitLab Runner 执行浅表克隆. 浅克隆使 Git 仅请求给定分支的最新一组更改,最多达到GIT_DEPTH变量定义的所需提交GIT_DEPTH .

这极大地加快了从 Git 存储库获取更改的速度,特别是如果存储库积压的事务由很多个大文件组成的积压很长时,因为我们有效地减少了数据传输量.

以下示例使 GitLab Runner 浅表克隆仅获取给定的分支; 它不会获取任何其他分支或标签.

Git strategy

在 GitLab Runner 8.9 中引入.

默认情况下,GitLab 配置为始终首选GIT_STRATEGY: fetch策略. 如果在磁盘上找到GIT_STRATEGY: fetch策略,则会重新使用现有的工作树. 这与GIT_STRATEGY: clone策略不同, GIT_STRATEGY: clone一样,如果找到了工作树,则会在克隆之前将其删除.

首选使用fetch ,因为它会减少要传输的数据量,并且不会真正影响您可能会从 CI 对存储库执行的操作.

但是, fetch确实需要访问以前的工作树. 使用时,这种运作良好, shelldocker执行,因为这些努力保持 worktrees,默认情况下尽量重复使用它们.

目前不适用于kubernetes执行器,并且在使用kubernetes docker+machine时有限制. 执行器总是克隆到临时目录中.

在 GitLab Runner 11.10 中引入.

允许您控制在何处克隆源. 如果您在 fork 工作流中大量使用大型存储库,则可能会产生影响.

从 GitLab Runner 的角度来看,前叉工作流存储为具有单独工作树的单独存储库. 这意味着 GitLab Runner 无法优化工作树的使用,您可能必须指示 GitLab Runner 使用它.

在这种情况下,理想情况下,您希望使 GitLab Runner 执行程序仅用于给定项目,而不是在不同项目之间共享,以使此过程更高效.

GIT_CLONE_PATH必须在$CI_BUILDS_DIR . 当前,不可能从磁盘选择任何路径.

Git clean flags

在 GitLab Runner 11.10 中引入.

GIT_CLEAN_FLAGS允许您控制是否要求对每个 CI 作业执行git clean命令. 默认情况下,GitLab 确保您的工作树在给定的 SHA 上,并且您的存储库是干净的.

设置为none时,将禁用 . 在非常大的存储库上,这可能是理想的,因为git clean是磁盘 I / O 密集型的. 使用GIT_CLEAN_FLAGS: -ffdx -e .build/控制GIT_CLEAN_FLAGS: -ffdx -e .build/ (例如)使您可以控制和禁用后续运行之间工作树中某些目录的删除,这可以加快增量生成的速度. 如果您重复使用现有计算机并拥有可用于构建的现有工作树,则效果最大.

有关GIT_CLEAN_FLAGS接受的确切参数,请参见的文档. 可用参数取决于 Git 版本.

在 GitLab Runner 13.1 中引入 .

allows you to modify git fetch behavior by passing extra flags.

有关更多信息,请参见GIT_FETCH_EXTRA_FLAGS文档 .

Fork-based workflow

在 GitLab Runner 11.10 中引入.

  • 使用基于分叉的工作流进行贡献.
  • 重用现有的工作树. 预先配置了存储库的预配置运行器.
  • 赛跑者仅分配给项目和所有分叉.

让我们考虑以下两个示例,一个使用shell executor,另一个使用docker executor.

假设您具有以下config.toml .

This :

  • 使用shell执行器,
  • 指定一个自定义/builds目录,其中将存储所有克隆.
  • 启用指定GIT_CLONE_PATH
  • 一次最多运行 4 个作业.

假设您具有以下 .

This config.toml:

  • 使用docker executor,
  • 在磁盘上指定将存储所有克隆的自定义/builds目录. 我们在主机上挂载/builds目录,以使其在后续运行之间可重复使用,并允许其覆盖克隆策略.
  • 默认情况下已启用,因此未启用指定GIT_CLONE_PATH功能.
  • 一次最多运行 4 个作业.

一旦配置了执行程序,就需要微调.gitlab-ci.yml .

Our pipeline will be most performant if we use the following .gitlab-ci.yml:

上面配置了:

  • 浅克隆 10,以加快后续git fetch命令的速度.

为什么要使用$CI_CONCURRENT_ID ? 主要原因是要确保使用的工作树在项目之间不冲突. $CI_CONCURRENT_ID表示给定执行器中的唯一标识符,因此只要我们使用它来构造路径,就可以确保该目录不会与其他正在运行的并发作业冲突.

理想情况下,所有与作业相关的配置都应存储在.gitlab-ci.yml . 但是,有时希望使这些方案成为 Runner 配置的一部分.

在以上 Forks 的示例中,使此配置对于用户可发现可能是首选,但这会带来管理开销,因为需要为每个分支更新.gitlab-ci.yml . 在这种情况下,可能希望保持.gitlab-ci.yml克隆路径不可知,但是将其配置为 Runner.

我们可以使用以下规范扩展config.toml ,如果.gitlab-ci.yml不覆盖它,它将由 Runner 使用:

这使得克隆配置成为给定 Runner 的一部分,并且不需要我们更新每个 .