2022年12月12日 - Tomo Masakura    

GitLab CI/CD Variables [前編]

GitLab CI/CD Variablesの使い方・設定方法をまとめています。

GitLabのCI/CD変数はその名前の通りGitLab CI/CDで利用する変数です。CI/CD変数はそれ単体ではただの変数でしかありませんが、GitLabの様々な機能がこの変数を利用します。また、様々な要件に対応するために、CI/CD変数を設定方法も一つではありません。結果としてCI/CD変数をより複雑なものにしています。

このブログでは、前編としてCI/CD変数の使い方・設定方法を解説します。後編でCI/CD変数のベストプラクティスを紹介します。

CI/CD変数のよくある使い方

CIジョブで環境変数として利用する

CI/CD変数で最もよく使われるのは、次のようにGitLab CIジョブのスクリプトで環境変数として利用することです。

次の例では、Androidのアプリをapkaab形式の両方をリリースビルドしています。

build:
  stage: build
  image: eclipse-temurin:17-jdk
  variables:
    BUILD_ENV: Release
  script:
    # ./gradlew :base:bundleRelease と同じ
    - ./gradlew bundle$BUILD_ENV
    # ./gradlew assembleRelease と同じ
    - ./gradlew assemble$BUILD_ENV

CI/CD変数はジョブのscript: (before_script:after_script:含む)の処理では環境変数として展開されます。

この例では、CI/CD変数のBUILD_ENVの値をDebugに変更するだけで、デバッグビルドに変更できます。

開発ツールの設定

CI/CD変数がCIジョブのスクリプトで環境変数に設定されることを利用して、CIジョブで利用する開発ツールの設定をすることができます。

JavaのビルドツールであるGradle環境変数にて設定を変更できます。CI/CD変数にこれらの設定をしておくと、環境変数に値がコピーされ、Gradleがそれを読み取ることができます。

次の例では、Gradleの設定で利用できる環境変数GRADLE_OPTSGRADLE_USER_HOMEをCI/CD変数で設定しています。

variables:
  # Gradleデーモンの起動を抑止。
  GRADLE_OPTS: "-Dorg.gradle.daemon=false"
  # ダウンロードするGradleやパッケージの保存先をGitLabでキャッシュするために場所を変更。
  GRADLE_USER_HOME: ${CI_PROJECT_DIR}/build/.gradle

default:
  image: eclipse-temurin:17-jdk
  # CIジョブでGradleやパッケージを毎回ダウンロードしなくてもいいように
  # ダウンロードしたファイルをGitLabでキャッシュします。
  cache:
    key: gradle
    paths:
      - build/.gradle

build:
  stage: build
  script:
    - ./gradlew jar

check:
  stage: test
  script:
    - ./gradlew check

一つ目の例では、GRADLE_OPTS: "-Dorg.gradle.daemon=false"とし、Gradleデーモンの起動を抑止しています。./gradlew -Dorg.gradle.daemon=false jarと必要な設定をコマンドライン引数に含めると、ここで何をやっているのかわがわかりにくくなります。CI/CD変数経由で設定することで、./gradlew jarとjarファイルの作成をするというのがわかりやすくなり、なおかつ、CI/CD変数を一箇所修正するだけで、Gradleの設定変更ができます。

もう一つの例では、GRADLE_USER_HOME: ${CI_PROJECT_DIR}/build/.gradleとし、Gradleと必要なパッケージのダウンロード場所を標準の$HOME/.gradleから変更しています。これは、ダウンロードしたGradleやパッケージをGitLabでキャッシュし、CIジョブを高速化するためです。

GitLab CI/CDのキャッシュについては公式ドキュメントのCaching in GitLab CI/CDをご覧ください。

CIジョブの挙動を変える

CIジョブの挙動を変えるためにCI/CD変数を使うこともできます。

次の例では、成果物のZIP圧縮の高速化とソースコードの取得方法を変更しています。

default:
  image: eclipse-temurin:17-jdk

build:
  stage: build
  variables:
    # キャッシュや成果物ZIPでより高速なfastzipを使います。
    FF_USE_FASTZIP: "true"
    # デフォルトの`git fetch`ではなく、`git clone`でソースコードを取得するように。
    GIT_STRATEGY: clone
  script:
    - gradle jar
  artifacts:
    paths:
      - build/libs/*.jar

FF_USE_FASTZIP: "true"キャッシュや成果物のZIP圧縮を高速化するためにfastzipを使う設定です。

また、GIT_STRATEGY: cloneとすることで、ソースコードの取得をgit fetchのかわりにgit cloneを利用するよう設定しています。

設定の詳細や他の設定については公式ドキュメントのConfiguring runnersをご覧ください。

条件でCIジョブを起動する

特定のブランチのみCIジョブを実行するのような条件にも利用できます。

build:
  stage: build
  script:
    - echo run build
  rules:
    - if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH

この例では、デフォルトブランチにプッシュされたときのみジョブを起動するよう設定しています。

条件の書き方の詳細は公式ドキュメントのChoose when to run jobsGitLabのCI/CDで超重要なrulesの全てを理解するをご覧ください。

GitLab Environment

GitLab Environmentは本番環境・ステージング環境などにデプロイされたアプリケーションとGitLabのプロジェクトを関連付けるものです。GitLabのEnvironmentを使いこなせ!(.gitlab-ci.ymlで使う編)も参考になります。

  • 本番環境・ステージング環境・テスト環境デプロイしたアプリに、GitLabプロジェクトのEnvironmentからすぐにアクセスできます。
  • マージリクエストのブランチをデプロイしたアプリに、マージリクエストからすぐにアクセスできます。この機能はReview Appsと呼ばれます。

次の例では、本番環境とマージリクエストでアプリをデプロイし、GitLabからアクセスできるようにしています。

variables:
  APP_DOMAIN: example.jp

# 本番環境
# 手動でこのジョブを実行すると、本番環境にデプロイされます。
# GitLab Environmentsに`production`として
# `https://example.jp`が登録され、
# GitLabプロジェクトからすぐにアクセスできます。
deploy:production:
  stage: deploy
  script:
    - echo deploy to production
  environment:
    # 本番系のURLは https://example.jp
    name: production
    url: https://${APP_DOMAIN}
  when: manual

# マージリクエストのReview Apps
# マージリクエストのブランチをそれぞれ別々の環境を作成してでデプロイします。
# `15-fix-bug`ブランチは`https://15-fix-bug.examplejp`として
# GitLab Environmentsに登録され、
# マージリクエストにこのアプリへのリンクボタンが表示されます。
review:
  stage: deploy
  script:
    - echo deploy to review apps
  environment:
    # Review AppsのURLは https://15-fix-bug.example.jp (`15-fix-bug`ブランチの場合)
    name: review/$CI_COMMIT_REF_NAME
    url: https://${CI_COMMIT_REF_SLUG}.${APP_DOMAIN}
    on_stop: stop:review
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"

stop:review:
  stage: deploy
  script:
    - echo delete deployment
  environment:
    name: review/$CI_COMMIT_REF_NAME
    action: stop
  when: manual

サービスの環境変数

GitLab CIジョブでは、データベースなどをサービスとして起動することができます。CI/CD変数はこのサービスの環境変数にも設定されます。

次の例では、PostgreSQLデータベースをサービスとして起動し、アプリケーションテストを実行しています。

test:
  stage: test
  image: eclipse-temurin:17-jdk
  services:
    # テストのためのPostgreSQLサーバーを起動する。
    - postgres
  variables:
    POSTGRES_DB: app
    POSTGRES_USER: app
    POSTGRES_PASSWORD: p@assw0rd
  script:
    # データベースの初期化。
    - apt-get -qy update && apt-get -qy install postgresql-client
    - cat db/initialize.sql | PGPASSWORD=${POSTGRES_PASSWORD} psql -U ${POSTGRES_USER} -h postgres -d ${POSTGRES_DB}
    # アプリケーションのテスト。
    - export JDBC_URL=jdbc:postgresql://postgres:5432/${POSTGRES_DB}
    - export JDBC_USER=${POSTGRES_USER}
    - export JDBC_PASSWORD=${POSTGRES_PASSWORD}
    - ./gradlew test

CI/CD変数はCIジョブに環境変数として設定されるだけでなく、サービス(ここではPostgreSQL)の環境変数にも設定されます。PostgreSQLのDockerイメージPOSTGRES_で始まる環境変数で初期ユーザー・パスワード・データベースを設定できますので、CI/CD変数でPostgreSQLサーバーを初期化できます。

その後、データベーススキーマを初期化し、テストを実行しています。

Docker Imageの指定

CIジョブで利用するDocker Imageの指定にもCI/CD変数が利用できます。

次の例では、JDKの11と17でそれぞれでテストを実行しています。

default:
  # `eclipse-temurin:17`か`eclipse-temurin:11`になります。
  image: eclipse-temurin:$JAVA_VERSION

test:17:
  stage: test
  variables:
    JAVA_VERSION: 17
  script:
    - ./gradlew test

test:11:
  stage: test
  variables:
    JAVA_VERSION: 11
  script:
    - ./gradlew test

これ以外にも

ここまで紹介した以外にもCI/CD変数が利用できるところはたくさんあります。詳しくは公式ドキュメントのWhere variables can be usedをご覧ください。

CI/CD変数の設定

GitLab CIを使っている方は、.gitlab-ci.ymlファイルやGitLabプロジェクトの設定画面でCI/CD変数を設定できることや、CI_COMMIT_REFのような定義済みCI/CD変数があることをご存知でしょう。それ以外にも設定できる場所があり、優先順位があります。

  1. パイプラインの起動
    • GitLab Web UIからのマニュアル実行
    • トリガーパイプライン
    • スケジュール実行
  2. .gitlab-ci.yml内のCI/CD変数
    1. job:内のrules:
    2. job:内のparallel:matrix:
    3. job:内のvariables:
    4. グローバルセクションのvariables:
  3. プロジェクトCI/CD変数
  4. グループCI/CD変数
  5. インスタンスCI/CD変数
  6. 引き継がれたCI/CD変数
  7. RunnerのCI/CD変数
  8. 定義済みCI/CD変数

番号が小さい方が優先度が高く、同じ名前のCI/CD変数は上書きされます。

詳しくは公式ドキュメントのCI/CD variable precedenceをご覧ください。

一つ一つ簡単に解説します。

定義済みCI/CD変数

CIジョブのIDが設定されているCI_JOB_ID変数や、コミットのハッシュ値が設定されているCI_COMMIT_SHA変数など、予め定義されたCI/CD変数が多数用意されています。

次の例では、Gitのタグが発行されたときに、タグ名をアプリケーションのバージョン番号としてwarファイルを作成しています。

# `build.gradle` でプロパティからバージョン番号を読み取るようにしています。
#
# group 'com.example'
# version project.hasProperty('version') ? project['version'] : '0.0.0'

build:
  stage: build
  script:
    - ./gradlew war -Pversion=${CI_COMMIT_TAG}
  artifacts:
    paths:
      # `git tag 2.0.1 && git push --tags`で、
      # `build/libs/demo-2.0.1.war`ファイルが作成される。
      - build/libs/*.war
  rules:
    - if: $CI_COMMIT_TAG

.gitlab-ci.yml

.gitlab-ci.ymlファイル内のグローバルもしくは各ジョブのvariables:でCI/CD変数を設定できます。CI/CD変数の設定方法としては最もよく使われます。

# すべてのジョブで利用できます。
variables:
  VAR1: value1
  VAR2: value2

job1:
  variables:
    VAR1: job1_value1
    VAR3: https://example.jp/${VAR2}
  script:
    - echo $VAR1 # `job1_value1`と、ジョブ設定で上書きされます。
    - echo $VAR2 # `value2`と、グローバル設定のままです。
    - echo $VAR3 # `VAR2`変数を参照しています。

例ではVAR1 CI/CD変数をジョブのCI/CD変数で上書きし、VAR3 CI/CD変数はVAR2 CI/CD変数を展開しています。

変数の展開については後ほど解説します。

グローバルセクションのvariables:を引き継がない

グローバルセクションのvariables:に記述されたCI/CD変数は各ジョブでも上書きされない限り有効です。inherit:variables:falseにすると、グローバルセクションのvariables: CI/CD変数をすべて無視します。

variables:
  VAR1: value1

job1:
  inherit:
    # グローバルセクションの`variables:`を引き継ぎません。
    variables: false
  script:
    - echo $VAR1 # 何も表示されません。


job2:
   inherit:
     # `variables: true`は既定値です。
     variables: true
   script:
      - echo $VAR1 # `value1`

プロジェクト(もしくはグループ)のCI/CD変数

CI/CD変数をプロジェクト(もしくはグループ)に設定することもできます。

  • プロジェクトCI/CD変数 - GitLabプロジェクトの左サイドバーから設定->CI/CD->変数を展開します。
  • グループCI/CD変数 - GitLabグループの左サイドバーから設定->CI/CD->変数を展開します。グループ内のすべてのプロジェクトで利用できます。

プロジェクトのCI/CD変数設定

.gitlab-ci.ymlファイルへ記述するのと比べて、大きな違いがあります。

  • 設定・参照できるのがOwnerロールもしくはMaintainerロールのみ。
  • GitLabのデータベースに暗号化されて保管される。

このため、アクセストークン・パスワード・シークレットなどの秘匿情報を格納するのに向いています。

このCI/CD変数は、名前(キー)や値以外にもタイプなど細かい設定ができます。

プロジェクトのCI/CD変数の設定項目

  • Protected variable - 保護されたブランチ(一般的にはmainもしくはmaster)や保護されたタグ以外では設定されません。これらのブランチやタグのプッシュはMainteinerロール以上でしかできないため、それ未満のロールの開発チームのメンバーから値を隠す効果があります。
  • Mask variable - CIジョブのログへの値の出力を****に置き換え、隠します。うっかりミスで秘匿情報がCIジョブのログに表示され、漏洩することを防ぎます。
  • タイプ - Fileを選ぶと値がファイルに保存され、CI/CD変数には値ではなく、そのファイルのパスが設定されます。テキスト形式の認証用証明書などで活用できます。
  • Environment scope - 指定されたGitLab EnvironmentのCIジョブでのみ設定されます。productionstaging及びReview Apps環境などで値を切り替えるのに利用できます。

これらの設定の活用方法については後編のベストプラクティスにて解説します。

サービスにプロジェクトのCI/CD変数を設定する

ここで設定したCI/CD変数は、他で設定したCI/CD変数と異なり、CIジョブのサービスコンテナーの環境変数には設定されないことに注意してください。プロジェクト(もしくはグループやインスタンス)のCI/CD変数に設定した値をサービスコンテナーの環境変数に設定するには、次のようにします。

test:
  variables:
    POSTGRES_DB: app
    POSTGRES_USER: app
    # プロジェクトのCI/CD変数の値をコピーします。
    POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
  services:
    - postgres
  before_script:
    - apt-get -qy update && apt-get -qy install postgresql-client
  script:
    - echo 'select current_date;' | PGPASSWORD=${POSTGRES_PASSWORD} psql -U ${POSTGRES_USER} -h postgres -d ${POSTGRES_DB}

GitLabインスタンスのCI/CD変数

プロジェクト(もしくはグループ)のCI/CD変数だけでなく、GitLabインスタンスのCI/CD変数も用意されています。設定できる項目もプロジェクトのCI/CD変数と変わりはありません。

管理者エリアの設定->CI/CDを開き、変数を展開します。

GitLabインスタンスのCI/CD変数設定

ただし、GitLabインスタンスにどのようなCI/CD変数が設定されているかは利用者には分かりません。利用者の混乱を招きますので、乱用は避けてください。

RunnerのCI/CD変数

CIジョブが動作するRunnerでもCI/CD変数を設定できます。設定ファイル(config.toml)のenvironmentに設定します。

次の例では、RunnerにHTTPプロキシを設定しています。(このRunnerはHTTPプロキシを経由しないとインターネットにアクセスできない場所に設置されています)

[[runners]]
  name = "984d91d334c9"
  environment = ["http_proxy=http://proxy.example.jp:8080","https_proxy=http://proxy.example.jp:8080","no_proxy=localhost,127.0.0.1"]

RunnerのCI/CD変数もGitLabインスタンスのCI/CD変数と同様に、どのようなCI/CD変数が設定されているか利用者からは分かりません。乱用を避けてください。

パイプラインの手動実行

GitLabのパイプラインはリポジトリにプッシュされたことをトリガーにして起動するのが一般的ですが、それ以外にもマニュアル・API・スケジュールで実行することができます。

GitLabのプロジェクトのサイドメニューでCI/CD ->パイプラインでパイプラインページを表示させ、Run pipelineボタンをクリックすると、パイプラインを手動で実行できます。

パイプラインの実行

変数に任意のCI/CD変数を追加してRun pipelineでパイプラインを実行できます。ここで設定したCI/CD変数は優先度が最も高く、他のCI/CD変数を上書きします。

このパイプラインの手動実行画面に、必要なCI/CD変数をあらかじめ表示することもできます。

規定のCI/CD変数が設定されたパイプラインの実行

.gitlab-ci.ymlファイルのグローバルのvariables:に次のように記述してください。(各ジョブのvariables:では使えません)

variables:
  BUILD_ENV:
    description: "`Debug` or `Release`"
    value: Release

build:
   stage: build
   image: eclipse-temurin:17-jdk
   script:
     - ./gradlew bundle$BUILD_ENV
     - ./gradlew assemble$BUILD_ENV

もしくは、次のようにパイプラインのマニュアル実行ページのURLのクエリにCI/CD変数を埋め込むこともできます。

https://gitlab.example.jp/group1/project1/-/pipelines/new?var[BUILD_ENV]=Release

トリガーパイプライン

GitLabのトリガーパイプラインは、GitLab以外の様々なサービスからパイプラインを起動するための仕組みです。次のような用途でよく用いられます。

  • Slackなどのチャットツールにrelease appとキーワードが入力されたら、リリース用のCIジョブを起動する。
  • 社内システムでマネージャーが承認ボタンを押したら、リリース用のCIジョブを起動する。

パイプラインを起動するには、RESTful APIで次のようにします。

$ curl --request POST \
       --form token=<token> \
       --form ref=<ref_name> \
       --form "variables[VAR1]=value1" \
       https://gitlab.example.jp/api/v4/projects/<project_id>/trigger/pipeline

クラウドサービスのWebhook呼び出しの設定ではURLしか設定できないことがほとんどです。その場合、URLのクエリ文字列でトークンやCI/CD変数を設定できます。

https://gitlab.example.jp/api/v4/projects/<project_id>/ref/<ref_name>/trigger/pipeline?token=<token>&variables[VAR1]=value1

トークンはGitLabプロジェクトの設定-> CI/CD ->パイプラインのトリガーを展開し、トリガーを追加で作成したものを利用してください。

パイプライントリガーのトークン作成

このCI/CD変数は他のCI/CD変数より優先され、上書きされます。

スケジュール実行

GitLabでは定時にパイプラインを起動することもできます。大規模なe2eテストなどの時間のかかる処理を夜のうちに済ませたいときによく使われます。

このスケジュールパイプラインでもCI/CD変数を設定できます。

パイプラインのスケジュール実行の作成

ここで設定したCI/CD変数は他のCI/CD変数よりも優先され、上書きされます。

CI/CD変数の引き継ぎ

CI/CD変数はCIジョブのスクリプトに環境変数として設定されます。ですが、スクリプトで設定した環境変数がCI/CD変数に戻されることはありません。

次の例では、job1->job2の順に実行していますが、job1で設定した環境変数はjob2へは引き継がれません。

job1:
  script:
    - export VALUE1=job1

job2:
  script:
    - echo ${VALUE1} # 何も表示されません。
  needs:
    - job1

CI/CD変数の引き継ぎはこれを可能にします。

次の例は、プロジェクトの.nvmrcに記述されているNode.jsのバージョンを調べ、CIジョブでも同じバージョンのNode.jsを利用するようにしています。

detect:node:
  stage: .pre
  script:
    # `.nvmrc`ファイルには`v18.9.1`と記述されています。
    - echo NODE_VERSION=`cat .nvmrc | sed 's/^v//;'` > .env
  artifacts:
    reports:
      dotenv: .env

test:
  # このジョブでは`NODE_VERSION: 18.9.1`が設定されています。
  image: node:${NODE_VERSION}
  script:
    - npm run test

detect:nodeジョブで作成された.envファイルにはNODE_VERSION=18.9.1と記述されています。このファイルを利用して、以降のジョブではCI/CD変数に設定されます。

parallel:matrix:

.gitlab-ci.ymlファイルのvariables:でCI/CD変数を設定できますが、Node.jsの異なるバージョンでそれぞれテストするなどのCIジョブには不向きです。

次の例ではparallel:matrix:を利用して、Node.jsの複数のバージョン(19, 18, 16の三つのバージョン)でテストをしています。

test:
  stage: test
  image: node:${NODE_VERSION}
  before_script:
    - npm ci
  script:
    - npm test
  parallel:
    matrix:
      - NODE_VERSION:
          - '19'
          - '18'
          - '16'

二次元以上の組み合わせパターンにも対応しています。詳しくは公式ドキュメントのparallel:matrixをご覧ください。

なお、parallel:matrix:での設定はvariables:より優先度が高く、上書きします。

rules:

.gitlab-ci.ymlファイルの各ジョブのrules:で、条件に応じて変数を設定できます。

次の例では、デフォルトブランチとそうでないときでリリースビルドとデバッグビルドを切り替えています。

build:
  variables:
    BUILD_ENV: Debug
  script:
     - ./gradlew bundle${BUILD_ENV}
  rules:
    # デフォルトブランチのとき。
    - if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH
      variables:
         BUILD_ENV: Release
    # それ以外のとき。
    - when: on_success

なお、rules:内でのCI/CD変数の設定は各ジョブのvariables:よりも優先で、上書きされます。

extends:による継承

extends:を利用することで、ベースになるvariables:を上書きすることができます。

.base: # `.`で始まる名前はジョブとして認識されません。
  variables:
    VAR1: base
    VAR2: base

job:
  extends: .base
  variables:
    VAR1: job
  script:
    - echo VAR1=$VAR1 # VAR1=job
    - echo VAR2=$VAR2 # VAR2=base

よく似た機能にYAML anchorがありますが、こちらはベースとなるvariables:を破棄した上で上書きします。

.base: &base
  variables:
    VAR1: base
    VAR2: base

job:
  <<: *base
  variables:
    VAR1: job
  script:
    - echo VAR1=$VAR1 # VAR1=job
    - echo VAR2=$VAR2 # `VAR2`は未設定。

CI/CD変数の展開

CI/CD変数は$VAR1$マークをつけることで、他のCI/CD変数の値を展開できます。

variables:
  # `registry.gitlab.example.jp/group1/project1:main`のようになります。
  DOCKER_IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG
  POSTGRES_DB: app
  POSTGRES_USER: app
  POSTGRES_PASSWORD: p@ssw0rd

job:
  variables:
    # `jdbc:postgres://postgres:5432/app`となります。
    JDBC_URL: jdbc:postgres://postgres:5432/$POSTGRES_DB
    # `app`ではなく、`$POSTGRES_DB`という文字列となります。
    VALUE: $$POSTGRES_DB
  script:
    - echo run job.

CI/CD変数の展開は、$VAR1の他に${VAR1}%VAR1%もサポートしています。また、$VAR1と値を設定したいときは$$VAR1$マークを二つ重ねます。

このCI/CD変数の展開はGo言語で書かれたGitLab Runnerによって行われます。CIジョブのシェル(shやPowerShell Core)とは無関係です。${MESSAGE:-hello} (shの記法でMESSAGE変数が設定されていないときのデフォルト値をhelloとする)や$env:MESSAGE (PowerShellの環境変数の記法)などのシェル特有の記法は使えません。

逆に、script: (before_Script:after_script:を含む)はこのCI/CD変数は展開された上で環境変数に設定されます。CI/CD変数の展開の記法ではなく、CIジョブで利用しているシェルの環境変数へのアクセス方法を利用することになります。

Windows RunnerではPowerShellの変数と環境変数の両方に値が設定されています。どちらを使うこともできます。

windows:
  variables:
    USER_NAME: Taro
    # ここはCI/CD変数の展開記法を使う。
    MESSAGE: Hello, ${USER_NAME}
  script:
    - echo $MESSAGE 
    - echo "Hello, $USER_NAME" # PowerShell変数
    - echo "Hello, ${USER_NAME}" # PowerShell変数
    - echo "Hello, $env:USER_NAME" # 環境変数
    - echo "Hello, ${env:USER_NAME}" # 環境変数
  tags:
    - windows

CI/CD変数の展開の順序

CI/CD変数の展開はCI/CD変数の優先順位順に行われるのではなく、優先順位順の上書きがすべて完了してから、GitLab Runnerで展開されます。

次のように、各ジョブのvariables:で設定したCI/CD変数をグローバルのvariables:で展開できます。

variables:
  WEB_APP_URL: https://${WEB_APP_HOSTNAME}example.jp

production:
  script:
    - # WEB_APP_URL=https://example.jp 
    - ./ci/deploy.sh --url ${WEB_APP_URL}
  environment:
    name: production
    url: ${WEB_APP_URL}
  when: manual

staging:
  variables:
    WEB_APP_HOSTNAME: staging.
  script:
    - # WEB_APP_URL=https://staging.example.jp 
    - ./ci/deploy.sh --url ${WEB_APP_URL}
  environment:
     name: staging
     url: ${WEB_APP_URL}
  when: manual

review:
  variables:
    WEB_APP_HOSTNAME: ${CI_COMMIT_REF_SLUG}-review.
  script:
    - # WEB_APP_URL=https://6-foo-review.example.jp 
    - ./ci/deploy.sh --url ${WEB_APP_URL}
  environment:
     name: review/$CI_COMMIT_REF_NAME
     url: ${WEB_APP_URL}
     on_stop: stop:review
  rules:
    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'

stop:review:
   script:
      - echo delete deployment
   environment:
      name: review/$CI_COMMIT_REF_NAME
   when: manual

例のように、優先度の低いCI/CD変数(WEB_APP_URL)内で優先度の高いCI/CD変数(WEB_APP_HOSTNAME)を展開できます。

この挙動のため、同名のCI/CD変数を展開はうまくきません。次の例のように、CI/CD変数NODE_OPTSにオプションを追加していくのをやりたくなりますが、おかしなことになります。

variables:
  NODE_OPTS: --enable-fips

job:
  variables:
    NODE_OPTS: "$NODE_OPTS --experimental-fetch"
  script:
    # 次の行のようになります。
    # node $NODE_OPTS --experimental-fetch --experimental-fetch src/script.js
    - node $NODE_OPTS src/script.js

variables:以外でのCI/CD変数の展開も似たような仕様ですが、rules:のようにCI/CD変数展開ができないものや、使えるCI/CD変数に制限があるものもあります。詳しくは公式ドキュメントのVariables usageをご覧ください。

まとめ

GitLab CI/CD変数を使うGitLabの機能はたくさんあります。GitLab CI/CD変数を調べると、自然とGitLabのDevOpsの機能を知ることに繋がります。

GitLabは毎月新しいバージョンがリリースされ、そのたびに新機能が追加されています。GitLab CI/CD variablesをじっくり読んでみると、今までできなかったことができるようになっているかもしれません。定期的に読み返すことをおすすめします。

CI/CD変数を使う際のベストプラクティスは後編で後日公開します。

Gitlab x icon svg