kakakakakku blog

Weekly Tech Blog: Keep Learning!

Terraform で moved ブロックを使わなくても count を削除できる

Terraform で環境ごとにリソースの有無を制御する場合や段階的にリソースを有効化するような場合に count を三項演算子のように使って制御できる.

developer.hashicorp.com

しかし count を使うと aws_sqs_queue.sandbox[0] のようにリソース id にインデックスが付いてしまう.最終的に count を使った制御が不要になって常にリソースをデプロイする場合は moved ブロックが必要になるけど,リソース id の変更が面倒になって count をそのまま残しているようなコードも見たことがある.

developer.hashicorp.com

最近 Refactor modules というドキュメントを読んでいたら count を削除する場合は「Terraform 側で自動的に moved を提案してくれる」と書いてあった.これは知らなくて今までずっと moved を実装していた❗️もちろん歴史的な経緯も記録できるので明示的に moved を実装する方が推奨ではあると書いてある👌

When you add count to an existing resource that didn't previously have the argument, Terraform automatically proposes moving the original object to instance 0 unless you write a moved block that explicitly mentions that resource. However, we recommend writing out the corresponding moved block explicitly to make the change clearer to future readers of the module.

developer.hashicorp.com

実際に試してみる \( 'ω')/

1. count を使って Amazon SQS キューをデプロイする

まずは create_queue という変数名と count を使って Amazon SQS キューをデプロイする.

variable "create_queue" {
  type    = bool
  default = true
}

resource "aws_sqs_queue" "sandbox" {
  count = var.create_queue ? 1 : 0

  name                      = "sandbox-queue"
  receive_wait_time_seconds = 20
}

terraform plan を実行するとリソース id が aws_sqs_queue.sandbox[0] になっていてインデックスが付いている👀

$ terraform plan

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_sqs_queue.sandbox[0] will be created
  + resource "aws_sqs_queue" "sandbox" {
      + arn                               = (known after apply)
      + content_based_deduplication       = false
      + deduplication_scope               = (known after apply)
      + delay_seconds                     = 0
      + fifo_queue                        = false
      + fifo_throughput_limit             = (known after apply)
      + id                                = (known after apply)
      + kms_data_key_reuse_period_seconds = (known after apply)
      + max_message_size                  = 262144
      + message_retention_seconds         = 345600
      + name                              = "sandbox-queue"
      + name_prefix                       = (known after apply)
      + policy                            = (known after apply)
      + receive_wait_time_seconds         = 20
      + redrive_allow_policy              = (known after apply)
      + redrive_policy                    = (known after apply)
      + region                            = "ap-northeast-1"
      + sqs_managed_sse_enabled           = (known after apply)
      + tags_all                          = (known after apply)
      + url                               = (known after apply)
      + visibility_timeout_seconds        = 30
    }

Plan: 1 to add, 0 to change, 0 to destroy.

そして terraform apply を実行してからステートを確認すると aws_sqs_queue.sandbox[0] として登録されていた.

$ terraform state list
aws_sqs_queue.sandbox[0]

2. moved ブロックを使って count を削除する

もし count が不要になったら moved ブロックを実装すればインデックスなしのリソース id に移行できる.

resource "aws_sqs_queue" "sandbox" {
  name                      = "sandbox-queue"
  receive_wait_time_seconds = 20
}

moved {
  from = aws_sqs_queue.sandbox[0]
  to   = aws_sqs_queue.sandbox
}

terraform plan を実行するとリソースへの影響はなくステートを更新できることがわかる👌

$ terraform plan

Terraform will perform the following actions:

  # aws_sqs_queue.sandbox[0] has moved to aws_sqs_queue.sandbox
    resource "aws_sqs_queue" "sandbox" {
        id                                = "https://sqs.ap-northeast-1.amazonaws.com/354924239642/sandbox-queue"
        name                              = "sandbox-queue"
        tags                              = {}
        # (20 unchanged attributes hidden)
    }

Plan: 0 to add, 0 to change, 0 to destroy.

3. moved ブロックを使わずに count を削除する

最後は moved ブロックを実装せずに count を削除してみる.

resource "aws_sqs_queue" "sandbox" {
  name                      = "sandbox-queue"
  receive_wait_time_seconds = 20
}

terraform plan を実行すると moved ブロックがなくても aws_sqs_queue.sandbox[0] has moved to aws_sqs_queue.sandbox という同じ結果になっていた❗️

$ terraform plan

Terraform will perform the following actions:

  # aws_sqs_queue.sandbox[0] has moved to aws_sqs_queue.sandbox
    resource "aws_sqs_queue" "sandbox" {
        id                                = "https://sqs.ap-northeast-1.amazonaws.com/354924239642/sandbox-queue"
        name                              = "sandbox-queue"
        tags                              = {}
        # (20 unchanged attributes hidden)
    }

Plan: 0 to add, 0 to change, 0 to destroy.

そして terraform apply を実行してからステートを確認すると aws_sqs_queue.sandbox に変更されていた.

$ terraform state list
aws_sqs_queue.sandbox

まとめ

Terraform で count を削除する場合は「自動的に moved を提案してくれる」ことは今まで知らなくて試してみた❗️明示的に moved を実装する方が推奨ではあると書いてあるけど,実装しなくても OK というのは覚えておこうと思う👌