Optimizing GitLab for large repositories
Optimizing GitLab for large repositories
通常,由于克隆和签出所需的时间,在工作树中包含超过 5 万个文件的大型存储库通常需要特别考虑.
GitLab 和 GitLab Runner 可以很好地处理这种情况,但是需要优化的配置才能有效地执行其操作.
处理大型存储库的一般准则很简单. 以下各节将更详细地描述每个准则:
- 始终以增量方式获取. 请勿以导致重新创建所有工作树的方式进行克隆.
- 始终使用浅克隆来减少数据传输. 请注意,由于 CPU 影响更大,这给 GitLab 实例带来了更多负担.
- 如果您大量使用基于 fork 的工作流,请控制克隆目录.
- 优化
git clean
标志,以确保删除或保留可能影响或加快构建速度的数据.
Shallow cloning
在 GitLab Runner 8.9 中引入.
默认情况下,GitLab 和 GitLab Runner 始终执行完整克隆. 虽然这意味着已收到来自 GitLab 的所有更改,但通常会导致接收额外的提交日志.
理想情况下,您应始终使用GIT_DEPTH
,该数字应较小,例如 10.这将指示 GitLab Runner 执行浅表克隆. 浅克隆使 Git 仅请求给定分支的最新一组更改,最多达到GIT_DEPTH
变量定义的所需提交GIT_DEPTH
.
这极大地加快了从 Git 存储库获取更改的速度,特别是如果存储库积压的事务由很多个大文件组成的积压很长时,因为我们有效地减少了数据传输量.
以下示例使 GitLab Runner 浅表克隆仅获取给定的分支; 它不会获取任何其他分支或标签.
variables:
GIT_DEPTH: 10
test:
script:
- ls -al
Git strategy
在 GitLab Runner 8.9 中引入.
默认情况下,GitLab 配置为始终首选GIT_STRATEGY: fetch
策略. 如果在磁盘上找到GIT_STRATEGY: fetch
策略,则会重新使用现有的工作树. 这与GIT_STRATEGY: clone
策略不同, GIT_STRATEGY: clone
一样,如果找到了工作树,则会在克隆之前将其删除.
首选使用fetch
,因为它会减少要传输的数据量,并且不会真正影响您可能会从 CI 对存储库执行的操作.
但是, fetch
确实需要访问以前的工作树. 使用时,这种运作良好, shell
或docker
执行,因为这些努力保持 worktrees,默认情况下尽量重复使用它们.
目前不适用于kubernetes
执行器,并且在使用kubernetes
docker+machine
时有限制. kubernetes
执行器总是克隆到临时目录中.
GitLab 还提供了GIT_STRATEGY: none
策略. 这会禁用任何由 GitLab 完成的fetch
和checkout
命令,要求您执行这些操作.
Git clone path
在 GitLab Runner 11.10 中引入.
GIT_CLONE_PATH
允许您控制在何处克隆源. 如果您在 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_FLAGS
. 在非常大的存储库上,这可能是理想的,因为git clean
是磁盘 I / O 密集型的. 使用GIT_CLEAN_FLAGS: -ffdx -e .build/
控制GIT_CLEAN_FLAGS: -ffdx -e .build/
(例如)使您可以控制和禁用后续运行之间工作树中某些目录的删除,这可以加快增量生成的速度. 如果您重复使用现有计算机并拥有可用于构建的现有工作树,则效果最大.
有关GIT_CLEAN_FLAGS
接受的确切参数,请参见git clean
的文档. 可用参数取决于 Git 版本.
Git fetch extra flags
在 GitLab Runner 13.1 中引入 .
GIT_FETCH_EXTRA_FLAGS
allows you to modify git fetch
behavior by passing extra flags.
有关更多信息,请参见GIT_FETCH_EXTRA_FLAGS
文档 .
Fork-based workflow
在 GitLab Runner 11.10 中引入.
遵循以上准则,让我们假设我们想要:
- 针对大型项目进行优化(目录中有超过 5 万个文件).
- 使用基于分叉的工作流进行贡献.
- 重用现有的工作树. 预先配置了存储库的预配置运行器.
- 赛跑者仅分配给项目和所有分叉.
让我们考虑以下两个示例,一个使用shell
executor,另一个使用docker
executor.
shell
executor example
假设您具有以下config.toml
.
concurrent = 4
[[runners]]
url = "GITLAB_URL"
token = "TOKEN"
executor = "shell"
builds_dir = "/builds"
cache_dir = "/cache"
[runners.custom_build_dir]
enabled = true
This config.toml
:
- 使用
shell
执行器, - 指定一个自定义
/builds
目录,其中将存储所有克隆. - 启用指定
GIT_CLONE_PATH
, - 一次最多运行 4 个作业.
docker
executor example
假设您具有以下config.toml
.
concurrent = 4
[[runners]]
url = "GITLAB_URL"
token = "TOKEN"
executor = "docker"
builds_dir = "/builds"
cache_dir = "/cache"
[runners.docker]
volumes = ["/builds:/builds", "/cache:/cache"]
This config.toml
:
- 使用
docker
executor, - 在磁盘上指定将存储所有克隆的自定义
/builds
目录. 我们在主机上挂载/builds
目录,以使其在后续运行之间可重复使用,并允许其覆盖克隆策略. - 默认情况下已启用,因此未启用指定
GIT_CLONE_PATH
功能. - 一次最多运行 4 个作业.
Our .gitlab-ci.yml
一旦配置了执行程序,就需要微调.gitlab-ci.yml
.
Our pipeline will be most performant if we use the following .gitlab-ci.yml
:
variables:
GIT_DEPTH: 10
GIT_CLONE_PATH: $CI_BUILDS_DIR/$CI_CONCURRENT_ID/$CI_PROJECT_NAME
build:
script: ls -al
上面配置了:
- 浅克隆 10,以加快后续
git fetch
命令的速度. - 自定义克隆路径,使我们可以在父项目和所有分支之间重用工作树,因为我们对所有分支使用相同的克隆路径.
为什么要使用$CI_CONCURRENT_ID
? 主要原因是要确保使用的工作树在项目之间不冲突. $CI_CONCURRENT_ID
表示给定执行器中的唯一标识符,因此只要我们使用它来构造路径,就可以确保该目录不会与其他正在运行的并发作业冲突.
Store custom clone options in config.toml
理想情况下,所有与作业相关的配置都应存储在.gitlab-ci.yml
. 但是,有时希望使这些方案成为 Runner 配置的一部分.
在以上 Forks 的示例中,使此配置对于用户可发现可能是首选,但这会带来管理开销,因为需要为每个分支更新.gitlab-ci.yml
. 在这种情况下,可能希望保持.gitlab-ci.yml
克隆路径不可知,但是将其配置为 Runner.
我们可以使用以下规范扩展config.toml
,如果.gitlab-ci.yml
不覆盖它,它将由 Runner 使用:
concurrent = 4
[[runners]]
url = "GITLAB_URL"
token = "TOKEN"
executor = "docker"
builds_dir = "/builds"
cache_dir = "/cache"
environment = [
"GIT_DEPTH=10",
"GIT_CLONE_PATH=$CI_BUILDS_DIR/$CI_CONCURRENT_ID/$CI_PROJECT_NAME"
]
[runners.docker]
volumes = ["/builds:/builds", "/cache:/cache"]
这使得克隆配置成为给定 Runner 的一部分,并且不需要我们更新每个.gitlab-ci.yml
.