[Terraform] “xxx is tainted, so must be replaced” と表示されたら

意図せずだったらカンタンに外せるよ
2023.01.30

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

どうも、ちゃだいん(@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.

参考情報

Command: untaint | Terraform | HashiCorp Developer