見出し画像

terraform apply_chdirオプションの罠 #485

terraformコマンドには -chdir オプションがあり、これでコマンド実行するディレクトリを指定できます。

私は当初 terraform apply をする時にこのオプションを使っており、各ディレクトリを指定してinitapplyをするようにしてしまっていました。

そうした方が丁寧かな?と考えたのと、-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を使うメリットはめちゃくちゃ大きいと感じるので、しっかり慣れていきたいですね。

ここまでお読みいただきありがとうございました!

いいなと思ったら応援しよう!