extendsを使って.gitlab-ci.yml内の重複処理をまとめる

2022.03.28

先に結論から

.gitlab-ci.yml内の以下のような重複処理は

validate-dev:
  stage: terraform-static-test
  script:
    - cd env/dev
    - terraform init -backend=false
    - terraform validate

validate-stg:
  stage: terraform-static-test
  script:
    - cd env/stg
    - terraform init -backend=false
    - terraform validate

validate-prod:
  stage: terraform-static-test
  script:
    - cd env/prod
    - terraform init -backend=false
    - terraform validate

以下のようにスッキリさせることができます。

.validate:
  stage: terraform-static-test
  script:
    - cd env/${ENV}
    - terraform init -backend=false
    - terraform validate

validate-dev:
  extends: .validate
  variables:
    ENV: dev

validate-stg:
  extends: .validate
  variables:
    ENV: stg

validate-prod:
  extends: .validate
  variables:
    ENV: prod

このエントリで言いたいことはこれだけです。もう少し詳しく知りたい方は続けてお読みください。

課題: 重複処理がたくさん

GitLabを使ってTerraformのコードを管理しているプロジェクトがありました。このTerraformのコードは複数環境に対応するため以下のようなディレクトリ構成になっています。よくあるディレクトリ構成かと思います。

.
├── env
│   ├── dev
│   │   ├── main.tf
│   │   .
│   │   .
│   ├── prod
│   │   ├── main.tf
│   │   .
│   │   .
│   └── stg
│       ├── main.tf
│       .
│       .
└── modules
    ├── hoge
    ├── fuga
    └── foo

terraform planなどのterraformの各種コマンドは env/devenv/stgといった各環境に対応したディレクトリにて実行します。具体的なコードはmodules以下にあり、各環境からmoduleを呼び出す際の引数値を変えることで環境ごとの差分に対応します。(devだけIP制限をかける、リソースのスペックを下げるなど)

このプロジェクトにおいて、GitLab Runnerを用いて、Terraformのコードの継続的なチェックを行なっています。具体的には以下です。

  • terraform fmt
  • terraform validate
  • tfsec
  • TFLint

terraform fmt以外はTerraformのルートディレクトリ(=root moduleがある、つまりterraformの各種コマンドを実行するディレクトリ)にて実行する必要があります。そのため環境分だけジョブを作成する必要がありました。例えばterraform validateの部分はこんな感じでした。

.gitlab-ci.ymlの一部

validate-dev:
  stage: terraform-static-test
  script:
    - cd env/dev
    - terraform init -backend=false
    - terraform validate

validate-stg:
  stage: terraform-static-test
  script:
    - cd env/stg
    - terraform init -backend=false
    - terraform validate

validate-prod:
  stage: terraform-static-test
  script:
    - cd env/prod
    - terraform init -backend=false
    - terraform validate

どう見てもイマイチです。こんな感じのがtfsecとTFLintの分もあります。

解決: extendsを使う

.gitlab-ci.ymlextendsというパラメーターを使うとこの重複処理をまとめることがわかったので採用しました。以下のように書きます。

.validate:
  stage: terraform-static-test
  script:
    - cd env/${ENV}
    - terraform init -backend=false
    - terraform validate

validate-dev:
  extends: .validate
  variables:
    ENV: dev

validate-stg:
  extends: .validate
  variables:
    ENV: stg

validate-prod:
  extends: .validate
  variables:
    ENV: prod
  1. まずベースとなる.validateジョブを定義します。
    先頭がドット(.)から始まるジョブは hide jobと呼ばれるジョブになり、無効化されそのジョブ自体は処理されなくなります。が、今回のように他のジョブのベースとすることができます。 (ベースとなるジョブは必ずしもhide jobである必要はなく、通常のジョブでもOKです。)
  2. .validateジョブでは、環境ごとに異なる部分を環境変数化しておきます。
  3. 次に環境ごとのジョブをそれぞれ定義します。extendsパラメーターを使い先程の.validateジョブを指定します。あとは環境ごとに異なるところ=環境変数の値を定義するだけです。