terraform apply_chdirオプションの罠 #485
terraformコマンドには -chdir オプションがあり、これでコマンド実行するディレクトリを指定できます。
私は当初 terraform apply をする時にこのオプションを使っており、各ディレクトリを指定してinitとapplyをするようにしてしまっていました。
そうした方が丁寧かな?と考えたのと、-chdirのようなオプションがわざわざ存在しているので、それを使わないといけないような気がしてしまいまして。
しかし-chdirを使うべきかどうかはもちろんケースバイケースで、私のケースでは不要なのにわざわざ使っていたせいで、terraform applyを実行するたびにリソースが重複して作成されてしまうという事態になりました。
発生状況
以下のようなディレクトリ構成です。
infrastructure
|- rds ----------- rds関係のtfファイル(モジュール)
|- ecs ----------- ecs関係のtfファイル(モジュール)
|- vpc ----------- vpc関係のtfファイル(モジュール)
|- main.tf
|- modules.tf # ここで各モジュールの変数に値を代入
` variables.tf
terraform applyはgithub actionsで自動化して実行していました。actionsの定義を抜粋します。
strategy:
fail-fast: false
matrix:
stack:
- vpc
- auth
- alb
- rds
- redis
- ecs
- ./
defaults:
run:
working-directory: ./infrastructure
steps:
- uses: actions/checkout@v3
- uses: aws-actions/configure-aws-credentials@master
with:
role-to-assume: arn:aws:iam::${{ env.AWS_ACCOUNT_ID }}:role/your-role-name
aws-region: ${{ env.AWS_REGION }}
- uses: hashicorp/setup-terraform@v2
with:
terraform_version: ${{ env.TF_VERSION }}
- name: Init
run: terraform -chdir=${{ matrix.stack }} init -upgrade -no-color
- name: Apply
run: terraform -chdir=${{ matrix.stack }} apply -no-color -auto-approve
上記の通り、各ディレクトリでinitとapplyを実行していました。これによってリソースの重複作成が発生してしまっていたのですが、原因がよくわかりませんでした。
原因: tfstateが読み込まれてない
調べると、tfstateの設定をルートディレクトリにのみ設置してたため、子ディレクトリでのコマンド実行においてそれが読み込まれず、常に新規作成になってしまっていたことが原因でした。
ルートディレクトリで、以下のようにremote stateで設定していました。
terraform {
required_version = "~> 1.9.5"
backend "s3" {
bucket = "my-application"
region = "ap-northeast-1"
key = "my-application.tfstate"
dynamodb_table = "my-terraform-state-lock"
}
required_providers {
aws = {
version = "~> 5.64.0"
}
}
}
しかしこれは子ディクトリには置いてなかったため、各ディレクトリでは常にstateが存在しない状態になってしまい、常に新規作成されていました。
解決策は簡単で、chdir オプションを使わずにルートでterraform applyするだけです。acitonsを以下のように修正できます。
strategy:
fail-fast: false
defaults:
run:
working-directory: ./infrastructure
steps:
- uses: actions/checkout@v3
- uses: aws-actions/configure-aws-credentials@master
with:
role-to-assume: arn:aws:iam::${{ env.AWS_ACCOUNT_ID }}:role/your-role-name
aws-region: ${{ env.AWS_REGION }}
- uses: hashicorp/setup-terraform@v2
with:
terraform_version: ${{ env.TF_VERSION }}
- name: Init
run: terraform init -upgrade -no-color
- name: Apply
run: terraform apply -no-color -auto-approve
なぜchdirを使ってしまったか
これは冒頭の理由に加えて、参照した別プロジェクトでもchdirオプションが使われていたことも油断してしまった原因でした。
ただ、その別プロジェクトでは問題が起きておらずでした。何が違ったかというと、その別プロジェクトでは各ディレクトリでtfstateの設定が定義されていた点です。
つまりディレクトリ毎にtfstateを読み込むように設定すればうまくいく可能性が高いです(僕のケースではそうするとコードが冗長になってしまうデメリットの方が大きかったので選択しませんでした)。
Terraformは奥が深い。
ただやはり、開発しているとTerraformを使うメリットはめちゃくちゃ大きいと感じるので、しっかり慣れていきたいですね。
ここまでお読みいただきありがとうございました!