大規模リポジトリに対するGitLabの最適化
ワークツリー内の50k以上のファイルで構成される大規模なリポジトリでは、クローンとチェックアウトに時間がかかるため、特別な配慮が必要になることがよくあります。
GitLabとGitLab Runnerはこのシナリオをうまく処理しますが、一連のオペレーションを効率的に実行するために最適化された設定が必要です。
大きなリポジトリを扱うための一般的なガイドラインはシンプルです。 各ガイドラインの詳細は以下のセクションで説明します:
- 常にインクリメンタルにフェッチしてください。 ワークツリーをすべて再作成するような方法でクローンを作成しないでください。
- データ転送を減らすために常にシャロークローンを使用します。 この場合、CPUへの影響が大きくなるため、GitLabインスタンスへの負担が増えることに注意してください。
- フォークベースのワークフローを多用する場合は、クローンディレクトリを制御してください。
-
git clean
フラグを最適化することで、ビルドに影響する可能性のあるデータを削除または保持し、ビルドを高速化します。
Shallow cloning
GitLab Runner 8.9 で導入されました。
GitLabとGitLab Runnerはデフォルトで常にフルクローンを行います。 GitLabからのすべての変更を受け取ることになりますが、余分なコミットログを受け取る結果になることがよくあります。
これは、GitLabGIT_DEPTH
Runner に浅いクローンを実行するように指示します。 浅いクローンは、 GIT_DEPTH
変数でGIT_DEPTH
定義したコミット数まで、指定した GIT_DEPTH
ブランGIT_DEPTH
チの最新の変更のみを Git にリクエスト 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: fetch
。 この GIT_STRATEGY: fetch
ストラテジーは、ディスク上にワークツリーが見つかった場合、既存のワークツリーを再利用します。これはGIT_STRATEGY: clone
ストラテジーとは異なり、クローンの場合、ワークツリーが見つかった場合、クローンする前に削除されます。
fetch
の使用は、転送するデータ量を削減し、CI からリポジトリに対して行うオペレーションに影響を与えないため、好まれます。
しかし、fetch
は前のワークツリーにアクセスする必要があります。shell
やdocker
のexecutorを使用する場合は、ワークツリーを保存し、デフォルトで再利用しようとするため、うまく機能します。
これはkubernetes
executorでは動作しませんし、docker+machine
を使用する場合にも制限があります。kubernetes
executorでは常にエフェメラルディレクトリにクローンされます。
GitLabはGIT_STRATEGY: none
。これはGitLabが実行するfetch
とcheckout
のコマンドを無効にし、自分で実行することを要求します。
git clone パス
GitLab Runner 11.10 で導入されました。
GIT_CLONE_PATH
これは、フォークワークフローで大きなリポジトリを多用する場合に意味を持ちます。
GitLab Runnerから見たフォークワークフローは、別々のリポジトリに別々のワークツリーとして保存されます。 つまり、GitLab Runnerはワークツリーの使い方を最適化することができず、GitLab Runnerに指示する必要があるかもしれません。
このような場合、理想的にはGitLab Runnerのexecutorを指定されたプロジェクトのみに使用し、異なるプロジェクト間で共有しないようにして、このプロセスをより効率的にしたいものです。
GIT_CLONE_PATH
$CI_BUILDS_DIR
現在のところ、ディスクから任意のパスを選ぶことは不可能です。
Git clean flags
GitLab Runner 11.10 で導入されました。
GIT_CLEAN_FLAGS
では、各 CI ジョブに対してgit clean
コマンドの実行を要求するかどうかを制御できます。デフォルトでは、GitLab は指定された SHA にワークツリーがあり、リポジトリがクリーンであることを保証します。
GIT_CLEAN_FLAGS
none
に設定すると無効になります。非常に大きなリポジトリでは、 はディスクI/Oを大量に消費するため、これが望ましいかもしれません。 (例) でこれを制御すると、後続の実行の間にワークツリー内のいくつかのディレクトリの削除を制御して無効にすることができ、インクリメンタルビルドを高速化できます。これは、既存のマシンを再利用し、ビルドに再利用できる既存のワークツリーがある場合に最大の効果を発揮します。git
clean
GIT_CLEAN_FLAGS: -ffdx
-e .build/
GIT_CLEAN_FLAGS
が受け付ける正確なパラメーターについては、git clean
のドキュメントを参照してください。利用可能なパラメーターはgitのバージョンに依存します。
Git fetch extra flags
GitLab Runner 13.1 で導入されました。
GIT_FETCH_EXTRA_FLAGS
を使用すると、追加のフラグを渡してgit fetch
の動作を変更できます。
詳しくはGIT_FETCH_EXTRA_FLAGS
ドキュメントをご覧ください。
フォークベースのワークフロー
GitLab Runner 11.10 で導入されました。
上記のガイドラインに従って、私たちがしたいことを想像してみましょう:
- 大きなプロジェクト(ディレクトリに50kファイル以上)に最適化します。
- 貢献するためにフォークベースのワークフローを使用してください。
- 既存のワークツリーを再利用します。 リポジトリと事前にクローンされたランナーを設定します。
- プロジェクトとすべてのフォークにのみ割り当てられたrunner。
shell
executorを使った例と、docker
executorを使った例を考えてみましょう。
shell
executor の例
次のような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
の executor を使用します、 - すべてのクローンが保存される
/builds
ディレクトリを指定します。 -
GIT_CLONE_PATH
を指定できるようにします、 - 一度に実行できるジョブは最大4つです。
docker
executor の例
次のような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
の executor を使用します、 -
/builds
すべてのクローンが保存されるディスク上の/builds
カスタム/builds
ディレクトリを/builds
指定します。 このディレクトリを/builds
マウント/builds
することで、次回以降の実行時に再利用できるようにし、クローン作成ストラテジーを上書きできるようにします。 - デフォルトで有効になっているため、
GIT_CLONE_PATH
を指定する機能は有効になりません。 - 一度に実行できるジョブは最大4つです。
私たちの.gitlab-ci.yml
executorを設定したら、.gitlab-ci.yml
を微調整する必要があります。
私たちのパイプラインは、以下の.gitlab-ci.yml
:
variables:
GIT_DEPTH: 10
GIT_CLONE_PATH: $CI_BUILDS_DIR/$CI_CONCURRENT_ID/$CI_PROJECT_NAME
build:
script: ls -al
を設定します:
- 後続の
git fetch
コマンドを高速化するため、10の浅いクローン。 - 親プロジェクトとすべてのフォーク間でワークツリーを再利用できるようにするためのカスタムクローンパス。
$CI_CONCURRENT_ID
を $CI_CONCURRENT_ID
使用する$CI_CONCURRENT_ID
主な理由は、使用されるワークツリーがプロジェクト間で衝突しないことを保証 $CI_CONCURRENT_ID
するためです。 は指定された executor 内で一意な識別子を表し、パスを構築するためにそれを使用する限り、このディレクトリが他の同時実行中のジョブと衝突しないことが保証されます。
カスタムクローンオプションをconfig.toml
理想的には、すべてのジョブに関連するコンフィギュレーションは、.gitlab-ci.yml
に保存されるべきです。 しかし、これらのスキームをRunnerコンフィギュレーションの一部にすることが望ましい場合もあります。
上記のForksの例では、このコンフィギュレーションをユーザーが発見できるようにすることが望ましいかもしれませんが、ブランチごとに.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
を更新する必要はありません。