TECHSTEP

ITインフラ関連の記事を公開してます。

GitLab includeでワークフローを再利用する

今回はGitLab CI/CDで利用できるキーワードの中から、.gitlab-ci.yml から同じProject上の別のファイル、別Project上のファイルを呼び出せる include について検証しました。

docs.gitlab.com

docs.gitlab.com

背景

ワークフローの定義ファイルを再利用することは、CI/CDをプロジェクトで運用する場合に重要です。パブリックに公開されたワークフローやプロジェクト共通のテンプレートを再利用することで、CI/CDの定義ファイルの記述量を削減したり、何度も同じ記述をコピーペーストしないことで、管理しやすいCI/CD定義ファイルの運用や人的ミスの削減を見込めます。

GitLabではCI/CDの実行を .gitlab-ci.yml で制御するのがデフォルトの設定です。例えば1つのGitLabプロジェクトで実行する全ての処理を .gitlab-ci.ymlスクリプトで記述すると、膨大な記述量となる場合もあります。GitLabでは include というキーワードを使うことで、同じProject上にある .gitlab-ci.yml 以外のファイルや、別Projectの定義ファイルを呼び出すことができます。

GitLabは現在6つの形式で include を利用できます。 components inputs は別の機会に触れるとして、ここでは他4つの利用方法を紹介します。

  • local : 同じProject上にある別ファイルを呼び出します。
  • project : 同じGitLabインスタンス上のプライベートな別Projectのファイルを呼び出します。
  • remote : 別のGitLabインスタンス上のファイルを呼び出します。
  • template : GitLabが公式に提供するテンプレートを呼び出します。
  • components : CI/CD componentという再利用可能なパイプラインのユニットを呼び出します。
  • inputs : 各 include を利用するときに変数を上書きするのに使用します。

なお、 include を利用するには、いくつかの制限事項があります。

  • include という名前のJobから呼び出す形でないと利用できません。
  • 呼び出すファイルの拡張子は yaml でないといけません。
  • project / remote / template / components の場合、呼び出し元のファイルが修正されてもCIは実行されません。
  • include を含むJobまたはパイプラインを再実行した場合、挙動が変化します。
    • Jobの場合: include で指定したファイルに修正を加えた後に再実行しても、その内容はJobに反映されません。
    • パイプラインの場合: include で指定したファイルに修正を加えた後に再実行すると、その内容はパイプラインに反映されます。
  • パイプラインあたりの include の最大数はデフォルトで150までです。

検証

ここから各手法を検証します。

include:local

docs.gitlab.com

include:local は同じProject上のファイルを呼び出す形です。1つのGitLab Projectで管理するような小規模プロジェクト、またはCI/CDの導入初期に利用するのがユースケースかと思います。

include:local を利用する場合は、 .gitlab-ci.yml に以下のように定義します。

include:
  - local: '<呼び出すファイルパスを指定>'

include:local を利用するうえでの注意事項は以下の通りです。

  • .gitlab-ci.yml と同じブランチ上のファイルしか対象にできません。
  • GIt submodule (ある Git リポジトリを別の Git リポジトリのサブディレクトリとして扱う) のパスでファイルを使用することはできません。

ここでは include-local-test というProject上に以下のようなファイルを配置しました。

.gitlab-ci.yml

build:
  stage: build
  script:
    - echo "Start include:local jobs."

include:
  - local: '.gitlab-ci.local.yml'
  - local: '/include/.gitlab-ci.local.yml'

.gitlab-ci.local.yml

test-from-include:
  stage: test
  script:
    - echo "This is from .gitlab-ci.local.yml."

include/.gitlab-ci.local.yml

deploy:
  stage: deploy
  script: 
    - echo "This is from include/.gitlab-ci.local.yml."

include:local.gitlab-ci.yml と別のディレクトリ上のファイルも呼び出し可能です。ここでは .gitlab-ci.local.yml include/.gitlab-ci.local.yml という2つのファイルを呼び出しています。

このProjectでCI/CDを実行すると、以下のように3つのStageに分かれて実行されます。

.gitlab-ci.local.yml を呼び出す test Jobを見ると、 This is from .gitlab-ci.yml.local (テキストを間違っておりました。。。) と表示されており、 .gitlab-ci.local.yml を呼び出しているのを確認できます。

include/gitlab-ci.local.yml を呼び出す deploy Jobも同様に確認できます。

include:project

docs.gitlab.com

include:project は同じインスタンス上の別Projectからファイルを参照します。複数のGitLab Projectにまたがって進むような大規模プロジェクトにおいて、include:project 専用のProjectを用意し、各Projectから利用することでプロジェクト内のCI/CDを利用しやすくする、などのケースが考えられます。

include:project は対象のプロジェクトとファイル名に加え、 ref というキーワードを使ってファイルの参照先 (デフォルトは HEAD を参照) を変更できます。

include:project は以下のように指定します。

include:
  - project: '<Project名を指定>'
    file: '<使用するファイル名を指定>'
    ref: '<ブランチ名、タグなどを指定 (オプション)>'

include:project の注意事項は以下の通りです。

  • パイプラインを実行するユーザーは include:project で指定したProjectのメンバーであり、適切な権限が必要です。
  • include:project で指定したファイルが更新されても、呼び出し元のCI/CDパイプラインは起動しません。またセキュリティの観点から、以下のように ref を使用して参照先を特定することが推奨されます。
    • 特定のSHAハッシュを指定する
    • 別プロジェクト上で protected branch / protected tag を使用する。この設定を適用した参照先は、Merge Requestなどの変更管理を通じて変更する確率が高くなります。

ここでは2つのGitLab Project ( include-project-test include-project-template-test ) を用意し、include-project-test から include-project-template-test 上のファイルを呼び出します。また include-project-template-test 上に feature ブランチを作成し、 ref を利用した場合も実施しています。

include-project-test/.gitlab-ci.yml

stages:
  - build
  - test
  - deploy

build:
  stage: build
  script:
    - echo "Start include jobs from another project."

include:
  - project: 'fy0323/include-project-template-test'
    file: '.gitlab-ci.project.yml'
  - project: 'fy0323/include-project-template-test'
    file: '.gitlab-ci.project.yml'
    ref: feature

include-project-template-test/.gitlab-ci.project.yml

project:
  stage: test
  script:
    - echo "This is from .gitlab-ci.project.yml at include-project-template-test"

include-project-template-test/.gitlab-ci.project.yml at feature branch

project-from-feature:
  stage: deploy
  script:
    - echo "This is from .gitlab-ci.project.yml at include-project-template-test"
    - echo "The branch name is feature."

include-project-test でCI/CDパイプラインを実行すると、以下のように3つのJobを実行します。 test Jobは include-project-template-testmain ブランチから、 deploy Jobは feature ブランチから呼び出しています。

それぞれのJobを見ると、確かに呼び出されていることを確認できます。

include:remote

docs.gitlab.com

include:remote は別インスタンス上のファイルを対象とする時に使用します。正直利用用途があまり浮かばなかったですが、例えば何らかの理由でGitLab Self-managedインスタンス / SaaSを複数利用しており、あるProjectのテンプレートを別のインスタンスでも利用したい場合、インスタンスをまたいでテンプレートを利用できます。ただし本機能は、参照元のProjectがPublicな場合に限り利用可能です。

include:remote は以下のように利用します。

include:
  - remote: '<GitLabインスタンスのURLを含むファイルパスを指定>'

include:remote を利用するうえでの注意事項は以下の通りです。

  • remote のターゲットにできるのは、 GET リクエストでアクセス可能なPublic Projectが対象です。
  • 認証情報を付与してのURLアクセスはサポートされていません。そのためPrivate Projectの利用は基本的にできません。

今回は include-remote-test というProjectで検証します。リモートURLには、以前作成したSelf-managedインスタンス上に作成したPublic Projectを使用しました。

.gitlab-ci.yml では以下のように指定します。

build:
  stage: build
  script:
    - echo "Start jobs from include:remote."

include:
  - remote: 'https://<GitLabインスタンスURL>/root/include-remote-template-test/-/raw/main/.gitlab-ci.remote.yml'

なお、リモートURLは、参照先リポジトリの以下の場所から取得できます。

パイプラインを実行すると、リモートURLから定義ファイルを取得し、問題なく処理が完了したのを確認します。

test jobを見ると、確かにリモートURLが呼び出され、定義された内容が呼び出されていることを確認できます。

include:template

docs.gitlab.com

include:template はGitLabの提供するテンプレートを利用する方法です。自分たちでイチからテンプレートを用意せずとも利用可能なので、用途に合ったものがあれば積極的に利用するのが良いと思います。

include:template は以下のように利用します。

include:
  - template: '<利用するテンプレートファイル名を指定>'

include:template の注意事項は以下の通りです。

  • include:templateで利用できるテンプレートはこちらに配置されています。ただし、すべてのテンプレートが include:template で利用できるわけではないため、利用前には各テンプレート中のコメントを確認する必要があります。

今回は Bash.gitlab-ci.yml というテンプレートを指定し、CI/CDから Bashスクリプトを呼び出します。

.gitlab-ci.yml は以下のように指定します。

build:
  stage: build
  script:
    - echo "Start jobs from include:template."

include:
  - template: Bash.gitlab-ci.yml

上記ファイルを配置し、問題なければパイプラインが完了します。Jobを確認すると、 Bash.gitlab-ci.yml で定義した内容が実行されているのを確認できます。

その他

Nested include

docs.gitlab.com

include入れ子構造で呼び出すことも可能です。 .gitlab-ci.yml から include で呼び出されるテンプレート内部で、さらに別のテンプレートを呼び出すことで、ワークフローのメンテナンス性と再利用性を向上することができます。

なお、Nested includeは1つのパイプラインあたり150ファイルが上限です。