【Terraform】lifecycleのprevent_destroyでリソースの意図しない削除を防ぐ
概要
Terraformのlifecycleブロックのprevent_destroyというオプションについての記事です。
このオプションを設定することで、重要なリソースが意図せず削除されるのを防ぐことができます。
設定を変更するとリソースが作り直される場合がある
リソース属性の変更内容によっては、既存のリソースを直接更新することができない場合があります。このようなケースでは、Terraformはクラウドプロバイダーの仕様に従い、現在のリソースを削除して新しいリソースを作り直します。
例えば、AzureのパブリックIPリソースにzones属性を追加する変更を行うと、forces replacementというメッセージが表示され、リソースが作り直される計画が立てられることがあります。これは以前に以下の記事を書いているときに遭遇した事例です。
terraform plan
# ... 略
Terraform will perform the following actions:
# module.public_ip.azurerm_public_ip.main must be replaced
-/+ resource "azurerm_public_ip" "main" {
+ fqdn = (known after apply)
~ id = "/subscriptions/****/resourceGroups/terraform-sample-dev-rg/providers/Microsoft.Network/publicIPAddresses/pip-terraform-import-test" -> (known after apply)
~ ip_address = "74.***.***.56" -> (known after apply)
- ip_tags = {} -> null
name = "pip-terraform-import-test"
- tags = {} -> null
- zones = [ # forces replacement
- "1",
- "2",
- "3",
] -> null
# (9 unchanged attributes hidden)
}
Plan: 1 to add, 0 to change, 1 to destroy.
zonesという項目にforces replacementと表示されていることやPlan: 1 to add, 0 to change, 1 to destroy.とあることから、既存リソースが削除され、再作成されようとしていることが分かります。
しかし、場合によっては再作成されると困るケースもあります。今回の例で言えば、パブリックIPの再作成によりIPアドレスが変更されてしまい、関連するシステムやサービスに影響を及ぼす可能性があります。
こういった問題を防ぐには、plan実行時に変更内容をちゃんと確認することが大事です。ですが、変更内容が多い場合は重要な変更点を見落とす可能性も高く、plan時の出力内容を確認するだけでは心許ないです。
対策: prevent_destroyを設定する
上に書いたような問題への対処法の1つがlifecycleのprevent_destroyです。
意図せぬ削除を防ぎたいリソースのresourceブロックにlifecycleのprevent_destroyを設定します。
resource "azurerm_public_ip" "main" {
name = var.name
resource_group_name = var.resource_group_name
location = var.location
allocation_method = "Static"
# リソースが再作成される変更
+ zones = ["1", "2", "3"]
+ lifecycle {
+ prevent_destroy = true
+ }
}
この状態でリソースが再作成されてしまうような変更を行い、planを実行すると、「このインスタンスは削除できない(Error: Instance cannot be destroyed)」というエラーになります。
terraform plan
# ...略
Terraform planned the following actions, but then encountered a problem:
# ...略
╷
│ Error: Instance cannot be destroyed
│
│ on ../../modules/public_ip/main.tf line 1:
│ 1: resource "azurerm_public_ip" "main" {
│
│ Resource module.public_ip.azurerm_public_ip.main has
│ lifecycle.prevent_destroy set, but the plan calls for this resource to be
│ destroyed. To avoid this error and continue with the plan, either disable
│ lifecycle.prevent_destroy or reduce the scope of the plan using the -target
│ option.
このように、lifecycle.prevent_destroyを使うことで、設定変更による意図しないリソース削除を防ぐことができます。
最後に
以上です!
大した内容ではないのですが、「リソースを作成し直されたら困る!」と分かっているものには確実にprevent_destroyを設定しておきたいですね。
Discussion