Terraformのディレクトリが増えても自動でGitHub Actionsの処理対象にする(動的matrix)
前提と課題
Terraformではtfstateを適度に分割するのが良いとされています。どの程度の粒度にまで分割するかは様々な考え方があるかと思いますが、例として以下のように分割していたとします。
一方でGitHub Actionsでこれらの各ディレクトリに対して何らかの同一の処理を実行したいとします。
├── envs
│ ├── stg
│ │ │── infra
│ │ │── service_a
│ │ │── ...
│ │ └── service_x
│ └── prd
│ │── infra
│ │── service_a
│ │── ...
│ └── service_x
└── modules
├── module_a
├── ...
└── module_x
GitHub Actionsにはbuild matrixという仕組みがあり、これを利用することで同一ジョブを複数ディレクトリに対して実行できます。
例えば、以下のジョブは各ディレクトリでterraform plan
を実行するジョブとなっています(plan
実行にあたって事前に必要なstepなどは割愛しています)。
jobs:
plan:
runs-on: ubuntu-20.04
strategy:
fail-fast: false
max-parallel: 1
matrix:
TF_DIR: # 以下にディレクトリを記載
- envs/stg/infra
- envs/stg/service_a
- ...
- envs/prd/service_x
env:
TF_DIR: ${{ matrix.TF_DIR }}
step:
//
- name: terraform plan ${{ env.TF_DIR }}
run: |
cd ${TF_DIR}
terraform plan
//
ただ、これだとリポジトリ内にtfstateを管理するディレクトリが増えるたびに、GitHub Actionsのワークフローにmatrix.TF_DIR
の値をひとつひとつ追記していかなければなりません。
これに対し、matrixを動的に設定することで、ワークフローファイルの修正を不要にします。
準備
まず、matrixを動的に設定するためのジョブを定義します。
jobs:
set-matrix:
runs-on: ubuntu-20.04
env:
TF_ROOT_DIR: .
outputs:
dirs: ${{ steps.find-tfstate-dirs.outputs.dirs }}
steps:
- uses: actions/checkout@v2
- name: Find tfstate dirs
id: find-tfstate-dirs
run: |
dirs=$(find ${TF_ROOT_DIR} -type f -name '*.tf' -exec dirname {} \; | grep -v 'modules\|\.terraform' | sort | uniq | jq -R -s -c 'split("\n")[:-1]')
echo $dirs # 確認用
echo "::set-output name=dirs::${dirs}"
find
コマンドにより、Terraformコードの存在するディレクトリを洗い出します。また、jqを使うことでディレクトリ一覧を以下の形式に変換しています。これは後ほどのジョブでfromJson()
関数を使うために必要な変換となります。
["envs/stg/infra","envs/stg/service_a", ... , "envs/prd/service_x"]
そして、この値はecho "::set-output name=dirs::${dirs}"
により、stepのoutputとして設定されます。
さらにstepのoutputは、以下の指定により、jobのoutputとして設定されます。
jobs:
set-matrix:
//
outputs:
dirs: ${{ steps.find-tfstate-dirs.outputs.dirs }}
ここまでで準備は完了です。
なお、ディレクトリ一覧洗い出しに際し、modules
や.terraform
を名前に含むディレクトリは除外するようにしています(tfstateを管理しているディレクトリとして想定していないため)。
matrixを動的に設定する
後は任意のジョブで、matrixを使います。
jobs:
set-matrix:
//
plan:
needs: set-matrix
runs-on: ubuntu-20.04
strategy:
fail-fast: false
max-parallel: 1
matrix:
TF_DIR: ${{ fromJson(needs.set-matrix.outputs.dirs) }}
env:
TF_DIR: ${{ matrix.TF_DIR }}
steps:
//
- name: terraform plan ${{ env.TF_DIR }}
run: |
cd ${TF_DIR}
terraform plan
//
GitHub Actionsの関数であるfromJson()
を以下のように使うことで、前段のジョブset-matrix
で生成した["envs/stg/infra","envs/stg/service_a", ... , "envs/prd/service_x"]
に基づき、複数のjobが実行されます。
matrix:
TF_DIR: ${{ fromJson(needs.set-matrix.outputs.dirs) }}
これで新しく作ったディレクトリをGitHub Actionsのワークフローに追加し忘れた・・・といったことから解放されます💪
参考
Discussion