🦊

GitLab CI/CD 親子パイプラインの変数優先度の罠

に公開

背景

GitLab CI/CD にはダウンストリームパイプラインという機能があり,パイプラインの中で別のパイプラインを呼び出すことができます。同じプロジェクトのパイプラインを呼び出す場合は親子パイプラインと呼ばれます。

たとえば,以下のような .gitlab-ci.yml 定義を書きます。

.gitlab-ci.yml
trigger-child-pipeline:
  trigger:
    include:
      - local: child.gitlab-ci.yml
child.gitlab-ci.yml
child-pipeline:
  stage: test
  script:
    - echo "Write test script here."

まず,最初の定義に書かれたパイプライン(親パイプライン)が実行されます。

次に,trigger:include:local キーワードで指定されたパイプライン定義ファイルが読み込まれ,同じプロジェクトの子パイプラインとして実行されます。

変数指定の罠

通常のパイプラインと同じように,子パイプラインにも変数を指定できます。

たとえば,以下のようにデフォルト変数およびジョブレベル変数を指定した場合,何が出力されるでしょうか?

.gitlab-ci.yml
variables:
  SOME_VAR: parent-default

trigger-child-pipeline:
  trigger:
    include:
      - local: child.gitlab-ci.yml
child.gitlab-ci.yml
variables:
  SOME_VAR: child-default

child-pipeline:
  stage: test
  variables:
    SOME_VAR: child-job-level
  script:
    - echo "SOME_VAR=$SOME_VAR"

「親ではなく子パイプライン,デフォルト変数ではなくジョブレベル変数が優先されるから SOME_VAR=child-job-level」でしょうか?

実はそうではなく,SOME_VAR=parent-default です。子パイプラインのジョブレベル変数を指定したつもりでも,親パイプラインのデフォルト変数が優先されてしまうのです。

子パイプラインの変数指定の挙動

この挙動は不具合ではなく仕様です。

trigger ジョブは trigger:forward:yaml_variables のデフォルト値が true のため,YAML 変数はデフォルトで子パイプラインに転送されます(trigger:forward の説明)。

転送された変数は子パイプラインではパイプライン変数となり,優先度比較で子パイプラインの YAML 定義(ジョブレベル変数やデフォルト変数)よりも上位のため,親パイプラインの変数が優先されるのです。

回避策

パイプライン変数の転送が不要であれば,trigger:forward:yaml_variables: false とするのがよいです。転送を止めるだけで,trigger ジョブ内(rules: など)では使い続けられます。

.gitlab-ci.yml
trigger-child-pipeline:
  trigger:
    include:
      - local: child.gitlab-ci.yml
    forward:
      yaml_variables: false

一方,指定した変数だけ転送させたい場合は,inherit:variables に変数名の配列を指定すればよいでしょう。ただし,子パイプラインのデフォルト変数より優先されることには引き続き注意が必要です。

.gitlab-ci.yml
trigger-child-pipeline:
  trigger:
    include:
      - local: child.gitlab-ci.yml
    inherit:
      - VARIABLE1
      - VARIABLE2

Discussion