[Terraform] “xxx is tainted, so must be replaced” と表示されたら
どうも、ちゃだいん(@chazuke4649)です。
tainted(汚染されている/壊れている)とは?
Terraformを使っていると、たまにapply実行後にエラーが起きて、期待していない状態のリソースが作成されることがあります。
そんな場合にterraform taint
コマンドでtaintedマークを付けておいて、次回apply時に再作成することが可能でした。
(ただし、現在ではtaintコマンドは非推奨で、代わりにterraform apply -replace=aws_instance.example
のような手法が推奨されています)
Forcing Re-creation of Resources - Terraform CLI | Terraform | HashiCorp Developer
Replace(再作成)したくない場合はどうする?
上記は明示的にtaintedマークをつけるのでよいですが、そうでなく、意図せずtaintedマークがついてて、再作成してほしくない場合もあります。
例えば以下のように、plan時にxxx is tainted, so must be replaced
と言われ、再作成する実行計画が返ってきて異変に気づきます。
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: -/+ destroy and then create replacement Terraform will perform the following actions: # aws_ec2_transit_gateway_vpc_attachment.network_dev is tainted, so must be replaced -/+ resource "aws_ec2_transit_gateway_vpc_attachment" "network_dev" { ~ id = "tgw-attach-xxxxxxxxxxxxxxx" -> (known after apply) tags = { "Name" = "example-vpcattach" } ~ vpc_owner_id = "111111111111" -> (known after apply) # (9 unchanged attributes hidden) } Plan: 1 to add, 0 to change, 1 to destroy. ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
こんな時に再作成したくない場合は、どうすればよいでしょうか?
答えはカンタンで、"terraform untaint" コマンドで、stateに登録されているtaintedマークを外せばOKのようです。
やってみた
現状確認する
上記例ではAWS Transit GatewayのVPCアタッチメントが対象のリソースとなります。
terraform state show
コマンドでstateがどうなっているか確認します。
すると、リソースアドレスの横にtaintedマークがついていました。
% terraform state show aws_ec2_transit_gateway_vpc_attachment.network_dev # aws_ec2_transit_gateway_vpc_attachment.network_dev: (tainted) resource "aws_ec2_transit_gateway_vpc_attachment" "network_dev" { appliance_mode_support = "disable" dns_support = "enable" id = "tgw-attach-xxxxxxxxxxxxx" ipv6_support = "disable" ... ## 以下割愛 }
stateファイル自体も見てみると、status に tainted と書かれていました。
{ "mode": "managed", "type": "aws_ec2_transit_gateway_vpc_attachment", "name": "network_dev", "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", "instances": [ { "status": "tainted", "schema_version": 0, "attributes": { "appliance_mode_support": "disable", ... ## 以下割愛
修正する
リソースアドレスを指定して、シンプルにterraform untaint
コマンドを実行します。
% terraform untaint aws_ec2_transit_gateway_vpc_attachment.network_dev Resource instance aws_ec2_transit_gateway_vpc_attachment.network_dev has been successfully untainted.
たったこれだけでした。
修正を確認する
taintedマークが取れていました。
% terraform state show aws_ec2_transit_gateway_vpc_attachment.network_dev # aws_ec2_transit_gateway_vpc_attachment.network_dev: resource "aws_ec2_transit_gateway_vpc_attachment" "network_dev" { appliance_mode_support = "disable" dns_support = "enable" id = "tgw-attach-xxxxxxxxxxxxx" ipv6_support = "disable" ... ## 以下割愛
再度stateファイルをpullし、diffしたところ、statusという項目自体なくなっていました。
% diff temp.tfstate temp2.tfstate 4c4 < "serial": 2, --- > "serial": 3, 38d37 < "status": "tainted",
これで、planすると、taintedマーク理由での強制的に再作成はなくなりました。
No changes. Your infrastructure matches the configuration.