为大型仓库优化极狐GitLab
由于克隆和检出需要时间,工作树中包含超过 50k 个文件的大型仓库可能需要超出流水线效率的更多优化。
极狐GitLab 和极狐GitLab Runner 可以很好地处理这种情况,但需要优化配置才能有效地执行其一组操作。
处理大型仓库的一般准则很简单。 以下各节更详细地描述了每条准则:
- 始终以增量方式获取。不要以导致重新创建所有工作树的方式进行克隆。
- 始终使用浅克隆来减少数据传输。请注意,由于更高的 CPU 影响,这会给极狐GitLab 实例带来更多负担。
- 如果您大量使用基于派生的工作流程,请控制克隆目录。
- 优化
git clean
标志,确保您删除或保留可能影响或加速构建的数据。
浅克隆
极狐GitLab 和极狐GitLab Runner 默认执行浅克隆。
理想情况下,您应该为 GIT_DEPTH
始终使用 10 这样的小数字,指示极狐GitLab Runner 执行浅克隆。
浅克隆使 Git 仅请求给定分支的最新更改集,最多可达到 GIT_DEPTH
变量定义的期望提交次数。
这样做加快了从 Git 仓库中获取更改的速度,因为我们有效地减少了数据传输量,特别是当仓库有很长的积压工作,其中包含大量大文件时。
以下示例使 runner 浅克隆仅获取给定分支;它不获取任何其他分支或标签。
variables:
GIT_DEPTH: 10
test:
script:
- ls -al
Git 策略
默认情况下,极狐GitLab 配置为使用 fetch
Git 策略,推荐用于大型仓库。
此策略减少了要传输的数据量,并且不会真正影响您可能从 CI 对仓库执行的操作。
Git 克隆路径
引入于极狐GitLab Runner 11.10。
GIT_CLONE_PATH
允许您控制克隆源的位置。如果您大量使用带有派生工作流的大型仓库,这可能会产生影响。
从极狐GitLab Runner 的角度来看,派生工作流存储为具有单独工作树的单独仓库。这意味着极狐GitLab Runner 无法优化工作树的使用。
在这种情况下,您希望使极狐GitLab Runner 执行器仅用于给定项目,而不是在不同项目之间共享,来提高此过程的效率。
GIT_CLONE_PATH
必须在$CI_BUILDS_DIR
中。目前,不能从磁盘中选择任何路径。
Git 清理标志
引入于极狐GitLab Runner 11.10。
GIT_CLEAN_FLAGS
允许您控制是否需要为每个 CI 作业执行 git clean
命令。默认情况下,极狐GitLab 确保您的工作树位于给定的 SHA 上,并且您的仓库是干净的。
GIT_CLEAN_FLAGS
在设置为 none
时被禁用。 在非常大的仓库上,这可能是需要的,因为 git clean
是磁盘 I/O 密集型的。使用 GIT_CLEAN_FLAGS: -ffdx -e .build/
(例如)控制它,允许您控制和禁用在后续运行之间删除工作树中的某些目录,可以加速增量构建。如果您重用现有机器,并拥有可重用于构建的现有工作树,将产生最大的影响。
有关 GIT_CLEAN_FLAGS
接受的确切参数,请参阅 git clean
的文档。可用参数取决于 Git 版本。
Git 抓取额外的标志
引入于极狐GitLab Runner 13.1。
GIT_FETCH_EXTRA_FLAGS
允许您通过传递额外标志来修改 git fetch
行为。
例如,如果您的项目包含大量 CI 作业不依赖的标签,您可以将 --no-tags
添加为额外的标志,使您的抓取更快,更紧凑。
同样,如果您的仓库不包含很多标签,--no-tags
在某些情况下会产生很大的不同。
如果您的 CI 构建不依赖于 Git 标签,那么值得一试。
基于派生的工作流程
引入于极狐GitLab Runner 11.10。
按照上面的指导,假设我们想要:
- 针对大型项目(目录中超过 50k 文件)进行优化。
- 使用基于派生的工作流程进行贡献。
- 重用现有的工作树。具有预配置的 runner,这些 runner 预克隆了仓库。
- Runner 仅分配给项目和所有派生项目。
让我们考虑以下两个示例,一个使用 shell
执行器,另一个使用 docker
执行器。
shell
执行器示例
假设您有以下 config.toml
。
concurrent = 4
[[runners]]
url = "GITLAB_URL"
token = "TOKEN"
executor = "shell"
builds_dir = "/builds"
cache_dir = "/cache"
[runners.custom_build_dir]
enabled = true
这个config.toml
:
- 使用
shell
执行器。 - 指定存储所有克隆的自定义
/builds
目录。 - 启用指定
GIT_CLONE_PATH
的能力。 - 一次最多运行 4 个作业。
docker
执行器示例
假设您有以下 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"]
这个 config.toml
:
- 使用
docker
执行器, - 指定磁盘上存储所有克隆的自定义
/builds
目录。我们托管挂载/builds
目录,使其在后续运行之间可重用,并允许覆盖克隆策略。 - 不启用指定
GIT_CLONE_PATH
的功能,因为它默认启用。 - 一次最多运行 4 个作业。
我们的 .gitlab-ci.yml
一旦我们配置了执行器,我们需要微调 .gitlab-ci.yml
。
如果我们使用以下 .gitlab-ci.yml
,我们的流水线性能最高:
variables:
GIT_CLONE_PATH: $CI_BUILDS_DIR/$CI_CONCURRENT_ID/$CI_PROJECT_NAME
build:
script: ls -al
此 YAML 设置配置自定义克隆路径。此路径使得在父项目和分支之间重用工作树成为可能,因为我们对所有分支使用相同的克隆路径。
为什么使用 $CI_CONCURRENT_ID
?主要原因是确保使用的工作树不会在项目之间发生冲突。$CI_CONCURRENT_ID
表示给定执行器中的唯一标识符。
当我们使用它来构造路径时,这个目录不会与其他正在运行的并发作业发生冲突。
将自定义克隆选项存储在 config.toml
中
理想情况下,所有与作业相关的配置都应该存储在 .gitlab-ci.yml
中。
但是,有时希望将这些方案作为 runner 配置的一部分。
在上面的派生示例中,此配置可能是首选,但这会带来管理开销,因为需要为每个分支更新 .gitlab-ci.yml
。
在这种情况下,可能需要保持 .gitlab-ci.yml
克隆路径不可知,但使其成为 runner 的配置。
如果 .gitlab-ci.yml
没有覆盖它,我们可以使用 runner 的以下规范扩展我们的 config.toml
:
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
。