大規模リポジトリ向けにGitLabを最適化

ワークツリー内のファイルが50kを超えるような大規模リポジトリでは、クローンやチェックアウトに時間がかかるため、パイプラインの効率を超えた最適化が必要になることがあります。

GitLabとGitLab Runnerはこのシナリオをうまく処理しますが、一連のオペレーションを効率的に実行するために最適化された設定が必要です。

大きなリポジトリを扱うための一般的なガイドラインはシンプルです。各ガイドラインは以下のセクションで詳しく説明します:

  • 常にインクリメンタルにフェッチしてください。ワークツリーをすべて再作成するようなクローンはしないでください。
  • データ転送を減らすために常にシャロークローンを使用してください。CPUへの影響が大きくなるため、GitLabインスタンスに負担がかかることに注意してください。
  • フォークベースのワークフローを多用する場合は、クローンディレクトリを制御してください。
  • git clean フラグを最適化し、ビルドに影響したり高速化したりする可能性のあるデータを確実に削除または保持します。

Shallow cloning

GitLab Runner 8.9で導入されました。

GitLab と GitLab Runner はデフォルトでシャロークローンを行います。

理想的には、常にGIT_DEPTH 10のような小さな数字を GIT_DEPTH使うべきです。GIT_DEPTH これは GitLab Runner に浅いクローンを実行するように指示します。シャロークローンは、変数で定義したコミット数までのブランチの最新の変更のみを Git にリクエスト GIT_DEPTHさせます。

これにより、Gitリポジトリからの変更の取得が大幅に高速化されます。特に、リポジトリに大きなファイルからなる非常に長いバックログがある場合は、データ転送量を効果的に減らすことができます。

次の例では、Runner をシャロークローンにして指定したブランチだけを取得するようにしています。他のブランチやタグは取得しません。

variables:
  GIT_DEPTH: 10

test:
  script:
    - ls -al

Git strategy

GitLab Runner 8.9で導入されました。

デフォルトでは、GitLab はfetch Git 戦略 を使うように設定されており、大規模なリポジトリに推奨されています。このストラテジーは転送するデータ量を減らし、CIからリポジトリに対して行うオペレーションにはあまり影響を与えません。

Gitクローンパス

GitLab Runner 11.10で導入されました。

GIT_CLONE_PATH を使うと、ソースをクローンする場所をコントロールできるようになります。これはフォークワークフローで大きなリポジトリを多用する場合に意味があります。

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 にワークツリーがあり、リポジトリがクリーンであることを保証します。

GIT_CLEAN_FLAGSnone に設定すると無効になります。非常に大きなリポジトリでは、git clean がディスク I/O を大量に消費するため、これが望ましいかもしれません。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 の挙動を変更することができます。

たとえば、プロジェクトにCIジョブが依存しないタグが大量に含まれている場合、--no-tags を追加フラグに追加することで、フェッチをより高速かつコンパクトにすることができます。

また、リポジトリにタグがあまり含まれて_いない_場合、--no-tags場合によっては大きな違いが生まれます。CIビルドがGitタグに依存していないのであれば、試してみる価値はあるでしょう。

詳しくはGIT_FETCH_EXTRA_FLAGS ドキュメント を参照してください。

フォークベースのワークフロー

GitLab Runner 11.10で導入されました。

上記のガイドラインに従って、私たちがしたいことを想像してみましょう:

  • 大きなプロジェクト(ディレクトリに50kファイル以上)の最適化。
  • 貢献するためにフォークベースのワークフローを使用します。
  • 既存のワークツリーを再利用。リポジトリと一緒にクローンされるランナーをあらかじめ設定しておきます。
  • プロジェクトとすべてのフォークにのみ割り当てられたランナー。

shell Executor を使った例とdocker Executor を使った例を考えてみましょう。

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 Executor を使用します、
  • すべてのクローンが保存されるカスタム/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 Executor を使用します、
  • /builds すべてのクローンを格納するディスク上の /buildsカスタム/builds ディレクトリを /builds指定します。このディレクトリを/builds マウント /buildsすることで、次回以降の実行時に再利用できるようにし、クローン戦略を上書きできるようにします。
  • デフォルトで有効になっているため、GIT_CLONE_PATH を指定する機能は有効になりません。
  • 一度に最大4つのジョブを実行します。

私たちの.gitlab-ci.yml

Executor の設定ができたら、.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 に保存されるべきです。 しかし、これらのスキームをランナーの設定の一部にすることが望ましい場合もあります。

上記のForksの例では、この設定をユーザーが発見できるようにすることが望ましいかもしれませんが、これはブランチごとに.gitlab-ci.yml を更新する必要があるため、管理上のオーバーヘッドをもたらします。このような場合、.gitlab-ci.yml クローン経路は不可知論とし、Runnerの設定とすることが望ましいでしょう。

.gitlab-ci.yml がオーバーライドしない場合、ランナーによって使用される以下の仕様でconfig.toml を拡張することができます:

concurrent = 4

[[runners]]
  url = "GITLAB_URL"
  token = "TOKEN"
  executor = "docker"
  builds_dir = "/builds"
  cache_dir = "/cache"

  environment = [
    "GIT_CLONE_PATH=$CI_BUILDS_DIR/$CI_CONCURRENT_ID/$CI_PROJECT_NAME"
  ]

  [runners.docker]
    volumes = ["/builds:/builds", "/cache:/cache"]

これにより、クローン設定は与えられたRunnerの一部となり、.gitlab-ci.yml を更新する必要はありません。

Git フェッチキャッシュステップ

非常にアクティブなリポジトリで大量の参照やファイルがある場合は、Gitaly の pack-objects キャッシュを使うことを検討しましょう。pack-objects キャッシュ:

  • GitLabサーバー上のすべてのリポジトリに恩恵を与えます。
  • 自動的にフォークを行います。