タダです.
やったことないオペレーションで S3 で管理している Terraform の tfstate
をローカルで変更する作業を経験したので備忘録として記事に残しておきます.
前提
そもそもなぜ tfstate
をいじることになったのかというと,Terraform のコードと管理している AWS 環境で差分が発生したため,terraform import
を行う必要があったからです.S3 に tfstate
が入っているんだから直接いじることも可能だと思いますが,万が一誤ったリソースの情報を消してしまったりすると大変なためローカルでの tfstate
の変更を行うことにしました.
手動で変更してしまったリソースが terraform plan
で差分として出たイメージ
# aws_subnet.hoge_subnet will be updated in-place ~ resource "aws_subnet" "hoge_subnet" { id = "subnet-123456789101112" ~ tags = { - "test" = "hoge" -> null # (2 unchanged elements hidden) } ~ tags_all = { - "test" = "hoge" -> null # (2 unchanged elements hidden) } # (14 unchanged attributes hidden) }
行ったオペレーション
1,tfstate をローカルに持ってくる
terraform init
後にまずは手元に tfstate
を持ってきます.terraform state pull
を使って,アウトプットで別ファイルに書き出します.
❯❯❯ terraform state pull > hoge.tfstate
その後,provider
の設定を書いているファイルを編集し,backend "s3"
のセクションをコメントアウトし,terraform init
で作成された .terraform.lock.hcl
や .terraform
ディレクトリを削除します.
terraform { required_version = ">= 1.0.0" # backend "s3" { # ~中略~ # } required_providers { aws = { source = "hashicorp/aws" version = ">= 3.0" } } } provider "aws" { region = "ap-northeast-1" }
その後,再度 terraform init
を実行できたらローカルで tfstate
を変更できるようになったので差分を埋めることができます.
❯❯❯ terraform init Initializing the backend... Initializing provider plugins... - Finding hashicorp/aws versions matching ">= 3.0.0"... - Installing hashicorp/aws v4.5.0... - Installed hashicorp/aws v4.5.0 (signed by HashiCorp) Terraform has created a lock file .terraform.lock.hcl to record the provider selections it made above. Include this file in your version control repository so that Terraform can guarantee to make the same selections by default when you run "terraform init" in the future. Terraform has been successfully initialized! You may now begin working with Terraform. Try running "terraform plan" to see any changes that are required for your infrastructure. All Terraform commands should now work. If you ever set or change modules or backend configuration for Terraform, rerun this command to reinitialize your working directory. If you forget, other commands will detect it and remind you to do so if necessary.
2,tfstate を編集する
まずは terraform state show
で terraform import
する対象の状態を確認します.差分として出ている test
タグもない状態なので,これをいじって差分を埋めていきます.
❯❯❯ terraform state show -state=hoge.tfstate aws_subnet.hoge_subnet # aws_subnet.hoge_subnet: resource "aws_subnet" "hoge_subnet" { arn = "arn:aws:ec2:ap-northeast-1:123456789101112:subnet/subnet-123456789101112" assign_ipv6_address_on_creation = false availability_zone = "ap-northeast-1a" availability_zone_id = "apne1-az4" cidr_block = "10.0.0.0/24" enable_dns64 = false enable_resource_name_dns_a_record_on_launch = false enable_resource_name_dns_aaaa_record_on_launch = false id = "subnet-123456789101112" ipv6_native = false map_customer_owned_ip_on_launch = false map_public_ip_on_launch = true owner_id = "123456789101112" private_dns_hostname_type_on_launch = "ip-name" tags = { "Name" = "hoge-subnet" "Owner" = "tada" } tags_all = { "Name" = "hoge-subnet" "Owner" = "tada" } vpc_id = "vpc-123456789101112" }
次に terraform state rm
で対象リソースの state を消します.この後,ローカルの tfstate
の中から削除したリソースデータがなくなっているはずです.
❯❯❯ terraform state rm -state=hoge.tfstate aws_subnet.hoge_subnet Removed aws_subnet.hoge_subnet Successfully removed 1 resource instance(s).
そして, terraform import
で対象リソースを取り込んでコード側も差分が出ている tag
を追記した後,terraform state show
や terraform plan
の実行計画を見て差分がないことを確認できるはずです.ここまでで tfstate
をいじる作業は終わりです.
❯❯❯ terraform import -state=hoge.tfstate aws_subnet.hoge_subnet subnet-123456789101112 aws_subnet.hoge_subnet: Importing from ID "subnet-123456789101112"... aws_subnet.hoge_subnet: Import prepared! Prepared aws_subnet for import aws_subnet.hoge_subnet: Refreshing state... [id=subnet-123456789101112] Import successful! The resources that were imported are shown above. These resources are now in your Terraform state and will henceforth be managed by Terraform. terraform state show -state=hoge.tfstate aws_subnet.hoge_subnet ❯❯❯ terraform state show -state=hoge.tfstate aws_subnet.hoge_subnet # aws_subnet.hoge_subnet: resource "aws_subnet" "hoge_subnet" { arn = "arn:aws:ec2:ap-northeast-1:123456789101112:subnet/subnet-123456789101112" assign_ipv6_address_on_creation = false availability_zone = "ap-northeast-1a" availability_zone_id = "apne1-az4" cidr_block = "10.0.0.0/24" enable_dns64 = false enable_resource_name_dns_a_record_on_launch = false enable_resource_name_dns_aaaa_record_on_launch = false id = "subnet-123456789101112" ipv6_native = false map_customer_owned_ip_on_launch = false map_public_ip_on_launch = true owner_id = "123456789101112" private_dns_hostname_type_on_launch = "ip-name" tags = { "Name" = "hoge-subnet" "Owner" = "tada" "test" = "hoge" } tags_all = { "Name" = "hoge-subnet" "Owner" = "tada" "test" = "hoge" } vpc_id = "vpc-123456789101112" } ❯❯❯ terraform plan -state=hoge.tfstate
3,リモートの tfstate
にローカルの変更を反映する
最後にローカルで変更した tfstate
をリモート側に反映します.tfstate
をローカルに持ってくるときにコメントアウトした backend "s3"
のセクションを戻し, .terraform.lock.hcl
や .terraform
ディレクトリを削除して terraform init
します.backend "s3"
になっています.
❯❯❯ terraform init Initializing the backend... Successfully configured the backend "s3"! Terraform will automatically use this backend unless the backend configuration changes. Initializing provider plugins... - Finding hashicorp/aws versions matching ">= 3.0.0"... - Installing hashicorp/aws v4.5.0... - Installed hashicorp/aws v4.5.0 (signed by HashiCorp) Terraform has created a lock file .terraform.lock.hcl to record the provider selections it made above. Include this file in your version control repository so that Terraform can guarantee to make the same selections by default when you run "terraform init" in the future. Terraform has been successfully initialized! You may now begin working with Terraform. Try running "terraform plan" to see any changes that are required for your infrastructure. All Terraform commands should now work. If you ever set or change modules or backend configuration for Terraform, rerun this command to reinitialize your working directory. If you forget, other commands will detect it and remind you to do so if necessary.
最後に,terraform state push
でリモートの tfstate
に反映します.コマンド実行後,リモートの tfstate
がコマンド実行時間帯で更新されているはずです.そして,この状態で terraform plan
で実行計画を確認するとローカルで確認した結果と同じになっていれば目的の作業は完了です.
❯❯❯ terraform state push hoge.tfstate
まとめ
リモートの tfstate
をいじらずに安全に反映していくための作業を経験したので,やった作業をまとめました.初めてのオペレーションでわからないことが多い中,下記の参考記事をベースに対応したので大変助かりました...