株式会社ネットワールドのエンジニアがお届けする技術情報ブログです。
各製品のエキスパートたちが旬なトピックをご紹介します。

GitとCI/CDに関する知識ゼロのSEによる、GitLabのCI/CDパイプラインのキーワード解説 ~include 編~

皆様こんにちは。SEの小池と申します。

以前、GitLabのCI/CDパイプラインのキーワード解説で workflow を取り上げました。(こちら)
ほぼ筆者の自習メモと化しているこのキーワード解説の第2弾をお送りいたします。

今回はキーワード include の概要と具体例を用いた説明をします。

本記事の対象の方

  • GitLabのCI/CDパイプラインで.gitlab-ci.ymlファイルを分割したい方。
  • GitLabのCI/CDパイプラインで、別のプロジェクトの.gitlab-ci.ymlファイルを参照させたい方。
  • GitLabのCI/CDパイプラインのキーワードincludeについて情報収集中の方。
  • 他人が書いた.gitlab-ci.ymlincludeが多用されてて意味が分からず困っている方。

今回のブログのゴール

このブログのゴールはこちらです。


今回のゴール
  • GitLabのCI/CDパイプラインのキーワード include の概要を把握する。

このブログをお読みいただくにあたっての事前ご連絡事項

  • 本記事はSaaS版 (GitLab.com) の Enterprise Edition 15.7.0-pre における仕様をベースに記載しております。それ以外のエディションやバージョンではこの記事に記載の通りではない可能性がございます。
  • 本記事はGitやCI/CDに関する知識ゼロのSEによるなんちゃって記事です。GitLabのディープな使用法についてはGitLabの公式オンラインドキュメント (こちら) をご参照ください。

キーワード include の概要

includeは、外部のyamlファイルをCI/CDパイプラインに含めることができるグローバルキーワードです

GitLabは、基本的にはプロジェクトのリポジトリのルートにある.gitlab-ci.ymlファイルにCI/CDパイプラインの構成を記載します。
ただ、CI/CDパイプラインの内容が複雑になりすぎて1つのファイルに書ききれない、既にある別のプロジェクトのパイプラインを引用したい…といったご要望もあると存じます。
そういったときにincludeを使うことで、リポジトリのルートにある .gitlab-ci.yml 以外のyamlファイルをそのCI/CDパイプラインに取り込むことができます

概念をイメージ図で説明いたします。
まず、GitLabの任意のプロジェクトのリポジトリに、下図のようなファイルやディレクトリがあるとします。

ファイル.gitlab-ci.ymlにはステージ build で実行する ジョブ ビルドジョブ01 が構成されています。
ファイルtest.gitlab-ci.ymlにはステージ test で実行する ジョブ テストジョブ01 が構成されています。
イメージ図をわかりやすくするためにyamlファイルの中で日本語を使っています。ご了承ください・・・。

この状態でCI/CDパイプラインを実行すると、パイプラインにはステージ build と、ジョブ ビルドジョブ01 が生成・実行されます。
つまり、ファイル.gitlab-ci.ymlで構成したステージとジョブしか生成されず、ファイルtest.gitlab-ci.ymlで構成したステージとジョブは生成されません。

ここで、ファイルtest.gitlab-ci.ymlで構成したステージとジョブをCI/CDパイプラインで実行するために、キーワードincludeを使ってみましょう。
ファイル.gitlab-ci.ymlに、キーワードincludeと含める対象のyamlファイル名を記載します。

この状態でCI/CDパイプラインを実行すると、パイプラインにはステージ buildtest、ジョブは ビルドジョブ01テストジョブ01 が生成・実行されます。
この様にキーワードincludeを使用すると、ファイル.gitlab-ci.yml以外のyamlファイルに記載されたCI/CDパイプラインの構成を含めることができます。

この様に、include外部のyamlファイルをCI/CDパイプラインに含めることができます

先述のイメージ図では同じリポジトリにある異なるyamlファイルをincludeしましたが、以下のいずれかに該当するyamlファイルであればincludeすることができます。
なお、remoteの場合は認証をサポートしていないなどの制限があります。詳細はGitLab Docs (こちら) をご参照ください。

  • 同じプロジェクトのリポジトリにあるyamlファイル (local)。
  • 異なるGitLabプロジェクトのリポジトリにあるyamlファイル (project)。
  • HTTP/HTTPS リクエストでアクセスできる公開URLに存在するyaml (remote)。
  • テンプレートにあるyamlファイル (template)。
参考:`.gitlab-ci.yml` keyword reference | GitLab

includeはグローバルキーワードです。
したがって、includeはジョブの中で指定することはできません。
またyamlファイルの一部分だけを抜き出してincludeすることはできません。

キーワード include のユースケース

アプリケーション開発をしたことがない筆者が頑張って考えたキーワードincludeのユースケースを挙げます。

  1. yamlファイルの肥大化を防ぐために、分割したい場合。
  2. 同じGitLabインスタンスの別のプロジェクトで利用しているyamlファイルを再利用可能な場合。
  3. GitLabのリポジトリ以外で保管しているyamlファイルを参照したい場合。
  4. GitLabが公開しているテンプレートを利用する場合。

上記のほかにも少し応用的な使い方として、キーワードincludeとキーワードrulesを併せて使うことで、特定の条件を満たした時だけ任意のyamlファイルを含めるような処理を構成することも可能です

例えば以下のような.gitlab-ci.ymlファイルの場合、別の2つのyamlファイルをincludeしていますが、このうちtemplateで指定された方のyaml (9行目に指定されたyaml) にだけ「ローカルリポジトリのルートにreadme.mdがある場合にのみ含める」という条件が付いています。

buildjob01:
  stage: build
  script:
      - echo ステージ1のテストのジョブです。
      - sleep 10

include:
  - local: '/sample-dir/sample-security.yml'
  - template: Security/SAST.gitlab-ci.yml
    rules: 
      - exists:
          - "readme.md"

単純にyamlファイルを見やすくしたり、汎用的なyamlを参照させるだけでなく、上記のようにキーワードrulesを併せて使うことで「○○の時だけこのyamlファイルをincludeする」といったように条件を指定できます

include の超簡単な使い方の例

ここからは実際にキーワードincludeの使い方を、超簡単な例を用いて紹介してまいります。

ローカルに存在する別のyamlファイルを含める場合 (local)

ローカル、つまり、同じプロジェクトのリポジトリに存在する別のyamlを含める場合、明示的に include:localと指定するか、もしくはサブキーワードの指定なしで記載します。

ここでは、ローカルにある/test/sample.gitlab-ci.ymlを含めると仮定します。
ローカルにある/test/sample.gitlab-ci.ymlの内容は以下の通りであると仮定します。

testjob01:
  stage: test
  script:
      - echo このジョブはtestステージで実行されるサンプルジョブです。
      - sleep 10

includeする側である.gitlab-ci.ymlで、明示的にinclude:localと指定する場合は以下 (7, 8行目) のような記載になります。

buildjob01:
  stage: build
  script:
      - echo このジョブはbuildステージで実行されるサンプルジョブです。
      - sleep 10

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

キーワードincludeはサブキーワードを指定しない場合はデフォルトでローカルのリポジトリをチェックするので、以下 (7行目) のようにlocalを省略することも可能です。

buildjob01:
  stage: build
  script:
      - echo このジョブはbuildステージで実行されるサンプルジョブです。
      - sleep 10

include: '/test/sample.gitlab-ci.yml'

明示的にinclude:local:を書いた場合も、local:を省略した場合も同様に、CI/CDパイプラインはこんな感じになります。

同じプロジェクトのリポジトリに存在するファイルを含めているだけなので、とてもシンプルな使い方です。
キーワードincludeの試行や練習をする場合は、まずはローカルのyamlファイルのincludeからお試しいただくのがよいと存じます。

同じGItLabインスタンスの別プロジェクトに存在するyamlファイルを含める場合 (project)

同じGItLabインスタンスの別プロジェクトに存在する別のyamlを含める場合、そのプロジェクトのパスと、ファイルのパスを指定する必要があります。
includeしたいyamlファイルがあるプロジェクトをサブキーワードproject、yamlファイルのパスをfileでそれぞれ指定します。

ここでは、IncludeTestPJ01 というプロジェクトにある/sample-dir/sample-security.ymlを含めると仮定します。
また、プロジェクト IncludeTestPJ01 にある/sample-dir/sample-security.ymlの内容は以下の通りであると仮定します。

samplejob01:
  stage: test
  script:
      - echo これはプロジェクト IncludeTestPJ01 の /sample-dir/sample-security.yml です。
      - sleep 10

前述の通り、別プロジェクトに存在するyamlを含める場合は、以下の記載例のようにincludeしたいyamlファイルがあるプロジェクトをサブキーワードproject、yamlファイルのパスをfileでそれぞれ指定する必要があります。

# ### 記載例 ###
# ex.) 異なるプロジェクトに存在するyamlファイルをincludeする場合。
include:
   - project: '<includeしたいyamlファイルが存在するプロジェクトのパス>'
     file: '<includeしたいyamlファイルのパス>'

サブキーワードprojectに指定するプロジェクトのパスは、プロジェクトのURLからGitLabのFQDNやIPを除いた文字列となります。
このブログの例の場合、プロジェクトのURLはhttps://gitlab.com/ssg6/yaml-pj/includetestpj01なので、サブキーワード project で指定する値はssg6/yaml-pj/includetestpj01です。

つまり、今回のようにプロジェクトパスssg6/yaml-pj/includetestpj01にある、yamlファイル/sample-dir/sample-security.ymlをincludeしたい場合は以下のように記載します。

buildjob01:
  stage: build
  script:
      - echo ステージ1のテストのジョブです。
      - sleep 10

include:
   - project: 'ssg6/yaml-pj/includetestpj01'
     file: '/sample-dir/sample-security.yml'

上の.gitlab-co.ymlで構成されるCI/CDパイプラインは以下のようになります。

GitLabで汎用的に使用できるCI/CDパイプラインを構成しているyamlがある場合は、サブキーワードprojectでincludeする方法がかなり有効です。
社内やグループでCI/CDパイプラインを使用することが定着しているのであれば、参照専用のプロジェクトを作成して、そこにあるyamlファイルをincludeする運用をご検討いただくのもよいかと存じます。

任意のURLに存在するyamlファイルを含める場合 (remote)

任意のURLで公開されているyamlファイルを含める場合、そのファイルのURLをサブキーワードに指定する必要があります。
ここでは例として、Amazon S3で公開している以下のyamlファイルをincludeしてみます。

samplejob01:
  stage: test
  script:
      - echo これはAmazon S3で公開しているyamlファイルです。
      - sleep 10

サブキーワードremoteを用いたincludeの書き方は以下の通りです。

# ### 記載例 ###
# ex.) 任意のURLに公開されているyamlファイルをincludeする場合。
include:
   - remote: '<yamlファイルが公開されているURL>'

例として、Amazon S3で公開したyamlファイルのURLがhttps://tkoike-gitlab-yaml-koukai-20221214.s3.ap-northeast-1.amazonaws.com/awss3.gitlab-ci.ymlとすると、.gitlab.ci-ymlは以下のようになります。

buildjob01:
  stage: build
  script:
      - echo ステージ1のテストのジョブです。
      - sleep 10

include:
   - remote: 'https://tkoike-gitlab-yaml-koukai-20221214.s3.ap-northeast-1.amazonaws.com/awss3.gitlab-ci.yml'

上の.gitlab-co.ymlで構成されるCI/CDパイプラインは以下のようになります。

サブキーワードremoteを使う場合は、認証がサポートされていませんのでご注意ください。(2022/12/15時点)

テンプレートとして存在するyamlファイル含める場合 (template)

サブキーワードtemplate中央リポジトリ (こちら) にあるyamlファイルをincludeできます。
GitLabが売りにしている機能の一つに Auto DevOps というものがありますが、Auto DevOpsの実装の一部でもこのサブキーワードを使います。

サブキーワードtemplateの記載例は以下の通りです。
テンプレートのパスは、中央リポジトリであるこちらを基準とした相対パスを指定する必要があります。

# ### 記載例 ###
# ex.) サブキーワードtemplateの指定方法。
include:
   - template: '<GitLabの中央リポジトリに存在するyamlファイルへの基準とした相対パス>'

Auto DevOpsの一つであるSASTを実装する場合を例に挙げます。
2022/12/15現在、SASTのテンプレートは中央リポジトリからの相対パスSecurity/SAST.gitlab-ci.ymlにあります。
これをサブキーワードtemplateに指定します。

このSASTテンプレートをincludeする例がこちらです。

buildjob01:
  stage: build
  script:
      - echo ステージ1のテストのジョブです。
      - sleep 10

include:
   - template: Security/SAST.gitlab-ci.yml

上の.gitlab-ci.ymlで構成されるCI/CDパイプラインは以下のようになります。
なお、SASTのテンプレートにて自動的に構成されるジョブはリポジトリの内容によって変化するため、以下は一例となります。

前述の通りサブキーワードtemplateは一部のAuto DevOpsの実装時に使うため、初心者でもに目にすることが多いincludeの使い方です。
中央リポジトリからの相対パスが指定されていることを知ってさえいれば、シンプルな使い方のサブキーワードです。

注意点:「そのジョブを実行するステージがないよ」エラー

キーワードinclude利用時に注意すべき事項があります。
それは、includeする側・される側問わず、yamlファイルの中でキーワード stages を用いてステージを明示的に宣言している場合です。

includeする側・される側問わず、どちらか片方だけでstagesを宣言している場合、stagesを宣言している方のyamlで定義されたステージのみ利用できます。デフォルトのステージである.pre, build, test, deploy, .postを含め、stagesで明示的に宣言していないステージは利用することができません。
したがって、stagesを宣言していていない側のyamlに設定したジョブは、stagesを宣言している側のyamlのステージ構成を考慮してジョブを設定する必要があります。

includeする側・される側の両方でstagesを宣言している場合、利用できるステージはincludeする側のyamlで宣言されたステージのみとなります
したがって、includeされる側のyamlに設定したジョブは、includeする側のyamlのステージ構成を考慮してジョブを設定する必要があります。

以下の図はincludeする側でステージの定義をし、includeされる側でステージの定義をしていない場合です。
ファイル.gitlab-ci.ymlがincludeする側、ファイルsample.gitlab-ci.ymlがincludeされる側です。
この時、ファイルsample.gitlab-ci.ymlにある、ジョブsamplejob02は実行ステージが sample-stage となっています。
しかし、includeする側の.gitlab-ci.ymlでは、ステージ sample-stage が定義されていません。
このため、ジョブsamplejob02は実行するステージが存在しない状態となり、結果としてCI/CDパイプラインはエラーとなります。

以下の図はincludeする側でステージの定義はせず、includeされる側でステージの定義をしている場合です。
ファイル.gitlab-ci.ymlがincludeする側、ファイルsample.gitlab-ci.ymlがincludeされる側です。
この時、ファイル.gitlab-ci.ymlにある、ジョブbuildjob01は実行ステージが build となっています。
しかし、includeされる側の.gitlab-ci.ymlでは、ステージ build が定義されていません。
このため、ジョブbuildjob01は実行するステージが存在しない状態となり、結果としてCI/CDパイプラインはエラーとなります。

以下の図はincludeする側・される側の両方でステージの定義をしている場合です。
ファイル.gitlab-ci.ymlがincludeする側、ファイルsample.gitlab-ci.ymlがincludeされる側です。
この場合において利用可能なステージは、includeする側のファイル.gitlab-ci.ymlで定義されたステージです。 つまり、includeされる側のファイルsample.gitlab-ci.ymlのジョブtestjob01は実行するステージ test がない状態です。
結果としてCI/CDパイプラインはエラーとなります。

この様に、includeする側・される側ともに、yamlファイルで不用意に stages を宣言していると、include時に思わぬところでエラーが出る場合があります。
stages を宣言する場合は、includeする側・される側のyamlファイルの既存ジョブの設定を考慮してください。
stages を宣言しない場合は、デフォルトステージである.pre, build, test, deploy, .postでジョブを実行するように設定してください。
また、GitLabのGUIにあるCI/CDパイプラインのエディタを使って.gitlab-ci.ymlを編集すると、ステージがないために実行できないジョブがある場合は編集画面 (GUI) にエラーメッセージが表示される仕様になっているので、ご活用ください。

最後に

この度はGitもCI/CDもよくわかっていないど素人SEによるGitLab検証ブログをお読みいただき、誠にありがとうございます。
このブログの目標は以下のとおりでしたが、皆さまはいかがでしたでしょうか。


今回のゴール
  • GitLabのCI/CDパイプラインのキーワード include の概要を把握する。

CI/CDパイプラインのキーワードはたくさんあります。
サブキーワードが4種類ありますが、どれも基本的には「別のyamlファイルに記載されたCI/CDパイプライン構成を含める」ということには変わりないので、覚えてしまえばシンプルなキーワードです。
もし、会社やグループで一部のCI/CDパイプラインの汎用化をしている場合、そのyamlファイルの内容をコピーするのではなく、includeで含めるという方法もご検討いただければと存じます。

この記事がGitLabを触り始めた方の一助となれば幸いにございます。


GitLabに関するお問い合わせは、以下のフォームからお願い致します。
GitLab製品 お問い合わせ

今までのGitLabの検証ブログはこちらです。
GitLab カテゴリーの記事一覧 - ネットワールド らぼ

GitLab操作デモ動画 (基本編) を作ってみました。(音声の録音は自宅でiPhoneのボイスメモ使うという超低クオリティですが…。)
つたない内容ではありますが、ご興味がおありでしたら是非ご視聴いただければと存じます。

www.youtube.com