movedブロック

movedブロックはTerraformのリソース名を変更するためのブロック。

既にapply済みでAWS上に作成済みのリソースの名称を変更したい場合に利用する。

以下の形式で記述する。

moved = {
  from = 変更前リソース名
  to   = 変更後リソース名
}

この記述をapplyすると変更前リソースが削除され、変更後リソースが作成される。

リソース名はterraform state listで確認できる。
» 参考: terraform show, terraform state show, terraform state listでリソースの情報を確認する

利用場面

リソース名を変更すると変更前リソースが削除されてしまう。

例えば以下のようなリソースがあるとする。

resource "aws_instance" "web" {
  ami           = "ami-xxxxxxxxxxxxxxxxx"
  instance_type = "t2.micro"
  ...
}

上記記述をapply後に、リソース名のwebweb_serverへ変更したいと考え、以下の様に変更したとする。

resource "aws_instance" "web_server" { # ← web を web_server に変更
  ami           = "ami-xxxxxxxxxxxxxxxxx"
  instance_type = "t2.micro"
  ...
}

この状態でapplyすると、aws_instance.webで作成したEC2インスタンスは一度削除され、aws_instance.web_serverのEC2インスタンスを新たに作成する。

ただ単にリネームしたいだけの場合はEC2インスタンスが落ちてしまうので稼働が一時的に止まってしまう。

実際にterraform planしてみると以下のように1台削除(destroy)、1台作成(add)として出力される。

# aws_instance.web will be destroyed
...
# aws_instance.web_server will be created
...
Plan: 1 to add, 0 to change, 1 to destroy.

対象リソースを触らずにリソース名だけを変更したい場合にmovedブロックを利用する。

movedブロックの利用

上記の例では以下のようにmovedブロックを利用する。
(ただしmoduleではなくルート直下のリソースの場合)

moved {
  from = aws_instance.web
  to   = aws_instance.web_server
}

terraform planを実行すると以下のように名前の変更だけが検出される。

# aws_instance.host has moved to aws_instance.web_server
...
Plan: 0 to add, 0 to change, 0 to destroy.

追加・削除ともに0件なのでEC2インスタンスは落ちることなくリソース名だけが変更される。

apply後にterraform state listを実行するとリソース名が変更されている。

$ terraform state list | grep aws_instance
aws_instance.web_server

movedブロックの作り方

Terraformの記述を変更し、movedブロックを追加する場合は一度planを実行してみるとよい。
その際、will be destroyedwill be createdと出力されている行にリソース名が出力されるので、それをmovedブロックのfromtoに記述する。

$ terraform plan -no-color | grep "will be"
  # aws_instance.web will be destroyed
  # aws_instance.web_server will be created

上記コマンドで一覧し、destroyedの方をfromcreatedの方をtoに記述すればよい。

Pull Request、CI/CDを含む開発フローにおけるmovedブロックの利用

チーム開発において開発者の手元でapplyしない運用をしている場合、リソース名の変更があった場合にはmovedブロックを利用する。
レビューを受けてからCI/CDでapplyする、というような運用の場合は以下のような手順となる。
(例としてGitHubでPullRequestを作成し、レビューが通ったらマージ→CI/CDでapplyする場合を想定)

  1. リソース名を変更し、movedブロックも追加する
  2. Pull Requestを上げてレビューを受ける
  3. レビューが通ったらマージ→CI/CDでapply
  4. movedブロックを削除する
  5. Pull Requestを上げてレビューを受ける
  6. レビューが通ったらマージ→CI/CDでapply

以上のように、「movedブロック付きのPull Request」とapply後にさらに「movedブロックを削除したPull Request」を作成すればよい。

movedブロックはルートモジュールに書く

movedブロックルートモジュールの中に書く。

例えば以下のようなディレクトリ構成の場合を考える。

.
├── envorinments
│   ├── production
│   │   └── main.tf
│   └── staging
│       └── main.tf
└── modules
    ├── a_module
    ├── b_module
    └── c_module

ルートモジュールがenvironments/production/main.tfenvironments/staging/main.tfで、modules以下のモジュールを利用しているとする。

この構成でモジュールのほうのリソース名を変更した場合movedブロックを変更したモジュール内に書きたくなる。

その場合でもmovedブロックはルートモジュール内に書く必要がある。