公開:2024年7月30日
1分で読めます
単一のリポジトリで複数のアプリケーションをホストするモノレポ用に、GitLab CI/CDパイプラインを作成する方法についてご紹介します。
モノレポを使用すると、単一のリポジトリで複数のアプリケーションのコードをホストできます。GitLabでこれを実現しようとすると、プロジェクト内の各ディレクトリに異なるアプリケーションのソースコードを配置することになります。この方法だとコードの保存場所をバージョン管理できるものの、GitLabのCI/CDパイプライン機能を最大限に活用するのは困難でした。しかしながら、新たな方法が登場しました!
通常、リポジトリには複数のアプリケーションのコードが格納されているため、複数のパイプライン設定が必要となります。たとえば、.NETアプリケーションとSpringアプリケーションがあるプロジェクトの場合、アプリケーションごとに異なるビルドジョブとテストジョブを実施している可能性があります。この場合、パイプラインを完全に切り離し、特定のアプリケーションのソースコードの変更が発生した場合のみ、各パイプラインを実行するのが理想的です。
このようなプロセスを技術的に実現するには、特定のディレクトリの変更に基づいて特定のYAMLファイルをインクルードする、プロジェクトレベルのパイプライン設定ファイル.gitlab-ci.yml
を用意します。.gitlab-ci.yml
パイプラインは、コードに加えられた変更に基づき、適切なパイプラインをトリガーするコントロールプレーンとして機能します。
GitLab 16.4より前のバージョンでは、プロジェクト内のディレクトリまたはファイルへの変更に基づいてYAMLファイルをインクルードすることはできませんでした。ただし、回避策を使えばこの機能を実現することは可能でした。
これからご紹介するモノレポプロジェクトの例では、異なるアプリケーション用に2つのディレクトリがあるとします。それぞれJavaアプリ用のjava
ディレクトリとPythonアプリ用のpython
ディレクトリがあります。それぞれのディレクトリには、各アプリをビルドするためのアプリケーション固有のYAMLファイルが含まれています。シンプルにプロジェクトのパイプラインファイルに両アプリケーションのパイプラインファイルをインクルードし、それらのファイルで直接ロジック処理を行います。
.gitlab-ci.yml
:
stages:
- build
- test
- deploy
top-level-job:
stage: build
script:
- echo "Hello world..."
include:
- local: '/java/j.gitlab-ci.yml'
- local: '/python/py.gitlab-ci.yml'
アプリケーション固有の各パイプラインファイルで「.java-common」もしくは「.python-common」という名前の非表示ジョブを作成します。これらのジョブは対応するアプリのディレクトリに変更が加えられた場合にのみ実行されます。デフォルトでは非表示ジョブは実行されず、通常は特定のジョブ設定を再利用するために使用されます。各パイプラインは、非表示ジョブを拡張して変更がないか監視するファイルを定めたルールを継承してから、パイプラインジョブを開始します。
j.gitlab-ci.yml
:
stages:
- build
- test
- deploy
.java-common:
rules:
- changes:
- '../java/*'
java-build-job:
extends: .java-common
stage: build
script:
- echo "Javaのビルド"
java-test-job:
extends: .java-common
stage: test
script:
- echo "Javaのテスト"
py.gitlab-ci.yml
:
stages:
- build
- test
- deploy
.python-common:
rules:
- changes:
- '../python/*'
python-build-job:
extends: .python-common
stage: build
script:
- echo "Pythonのビルド"
python-test-job:
extends: .python-common
stage: test
script:
- echo "Pythonのテスト"
この方法にはいくつかのデメリットがあります。たとえば、確実にルールに準拠するために、YAMLファイル内の他のジョブ用にそれぞれジョブを拡張しなければならないため、多くの冗長なコードが発生し、ヒューマンエラーが起きやすくなります。さらに拡張されたジョブでは重複するキーは持てないため、各ジョブにおいて独自のrules
ロジックを定義できません。定義しようとした場合、キーの競合が発生し、キーの値はマージされません。
結果として、java/
が更新されると、j.gitlab-ci.ymlジョブを含むパイプラインが実行され、python/
が更新されると、py.gitlab-ci.ymlジョブを含むパイプラインが実行されます。
GitLab 16.4では、パイプライン向けにrules:changes
を含むinclude
が導入されました。それまではinclude
にrules:if
を使用することはできたものの、rules:changes
は使用できませんでした。これは非常に強力なアップデートです。これにより、プロジェクトのパイプライン設定でinclude
キーワードを使用するだけで、モノレポのルールを定義できるようになりました。
新たな.gitlab-ci.yml
:
stages:
- build
- test
top-level-job:
stage: build
script:
- echo "Hello world..."
include:
- local: '/java/j.gitlab-ci.yml'
rules:
- changes:
- 'java/*'
- local: '/python/py.gitlab-ci.yml'
rules:
- changes:
- 'python/*'
その後、各アプリケーションのYAMLファイルにおいて非表示ジョブを何度も拡張せずに済むため、アプリケーションコードのビルドとテストだけに集中できます。これによって、より柔軟にジョブを定義できるようになり、エンジニアによるコードの書き直し作業が軽減します。
新たなj.gitlab-ci.yml
:
stages:
- build
- test
- deploy
java-build-job:
stage: build
script:
- echo "Javaのビルド"
java-test-job:
stage: test
script:
- echo "Javaのテスト"
新たなpy.gitlab-ci.yml
:
stages:
- build
- test
- deploy
python-build-job:
stage: build
script:
- echo "Pythonのビルド"
python-test-job:
stage: test
script:
- echo "Pythonのテスト"
上記の設定により、JavaとPythonのディレクトリがそれぞれ変更された場合にのみ、JavaまたはPythonのジョブをインクルードするという同じタスクを実行できます。実装時に考慮すべき点は、changes
を使用すると、ジョブが予期せぬタイミングで実行される可能性があるということです。新しいブランチやタグをGitLabにプッシュすると、changesルールは必ず「true」と評価されるため、rules:changes
の定義内容にかかわらず、ブランチへの最初のプッシュ時に、含まれるすべてのジョブが実行されます。こういった事態がなるべく起こらないようにするために、まずはフィーチャーブランチを作成してからマージリクエストを開いて開発を始めることをおすすめします。ブランチの作成時に最初にプッシュすることで、すべてのジョブが強制的に実行されるためです。
総括すると、モノレポはGitLabおよびCI/CDと組み合わせて、戦略的に利用できる手法です。新たなrules:changes
機能を含むinclude
キーワードの登場により、GitLab CIにおいてモノレポを使う際に適用できる優れたベストプラクティスができました。モノレポの利用をお考えの場合は、ぜひGitlab Ultimateの無料トライアルをご利用ください。