5
9

tfstate の操作チートシート

Posted at

こんにちは、エン・ジャパン株式会社のプラットフォームチームに所属している山﨑です。

弊社ではプラットフォームの構築にTerraform を利用しており、tfstate の操作を行なうことが多いのですが、操作を誤ると元の状態に戻すことが困難であったり、時間がかかってしまいます。

素早く安全に操作するため、どういった手法があるのか整理するとともに、ユースケースについて紹介します。

tfstate の操作手法の比較

tfstate は重要なファイルなので直接編集するのはなるべくやめましょう。また、ワークロードでは可能な限り Block Syntax(※1)で書くようにし、結果をPlanしたり、レビューを受けたりして安全に操作することを推奨します。

※1)後述しますが、moved Block やimport Block、removed Block など。

tfstate を操作する方法は2つに大別できます。

Terraform CLI はコマンドラインで操作し、Block Syntax はTerraform コードに記載してapply で操作します。

以下で比較します。

操作性の比較

操作方法 簡単な操作(※2) 安全な操作(※3) 備考
Terraform CLI O X ローカルから実行できる
Block Syntax X O Planで確認できる

※2)操作するための手順が少ないほど簡単な操作としています。
※3)実行する前に結果が分かるか、レビュー可能か、などの観点から判断している。

利用可能な操作の比較

多くの操作がBlock Syntaxで実施できます。

操作手法 import move
(同一のtfstate)
move
(別のtfstate)
remove
Terraform CLI O O O O
Block Syntax O O X O

操作方法

前提として、tfstate はクラウドに保存されている状態で始めます。tfstate の操作時にはバックアップを取っておきましょう。

Terraform CLI とBlock Syntax の操作方法について紹介します。

Terraform CLI

Terraform CLI を利用すれば、ローカルで全ての操作を行うことができます。

terraform state

tfstateの操作はこのコマンドでほとんど実行可能。

✅ terraform state list

どんなリソースを管理しているのか把握するのに便利。

# input
terraform state list

# output
module.vpc.aws_route_table.api[0]
module.vpc.aws_route_table.api[1]
module.vpc.aws_route_table.private[0]
module.vpc.aws_route_table.private[1]
module.vpc.aws_route_table.public

✅ terraform state show

特定のリソースの状態を把握するときに利用。

# input
terraform state show module.vpc.aws_route.public

# output
resource "aws_route" "public" {
    destination_cidr_block = "0.0.0.0/0"
    gateway_id             = "igw-xxx"
    id                     = "r-rtb-xxx"
    origin                 = "CreateRoute"
    route_table_id         = "rtb-xxx"
    state                  = "active"
}

✅ terraform state pull

現在の状態を取得。パイプを使えばファイル保存することが可能で、バックアップでよく使う。

# backup.tfstateに現在のtfstateをコピー
terraform state pull > backup.tfstate

✅ terraform state push

このコマンドは既存のtfstateを上書きするため注意すること。

指定したtfstateを既存のtfstateに上書きする。上書きする際にはtfstate のserial を変更しないといけない場合があるので注意。(その場合、直接tfstate を編集することになる)

# new.tfstateを新しいtfstateとする(上書きのため注意)
terraform state push new.tfstate

terraform state mv

Terraform v1.1.0 でmove Block が導入されたので、まずはそちらの利用を検討しましょう。

tfstateのリソースを操作する。オプションを付けなければ tfstate 内でリソース名を変更し、-state-out というオプションを付ければ別のファイルに移動(元のファイルからは削除)することが可能。

# リソース名を変更する
terraform state mv aws_instance.before aws_instance.after

# リソースを外に出力する
terraform state mv -state-out output.tfstate aws_instance.before aws_instance.after

terraform state rm

Terraform v1.7.0 でremoved Block が導入されたので、まずはそちらの利用を検討しましょう。

tfstate からリソースを削除する。実リソースを削除するわけではなく、あくまでtfstate 上から削除するだけ。

 # aws_instance.this をtfstate 上から削除する
 terraform state rm aws_instance.this

terraform import

Terraform v1.5.0 でimport Block が導入されたので、まずはそちらの利用を検討しましょう。

import はterraform state import ではなく、terraform import コマンドで実行する。

実リソースの情報をtfstate に取り込む。実リソースのID 指定方法はリソースによって異なるため公式ドキュメントを参考にすること。

# S3 Bucket
terraform import aws_s3_bucket.bucket bucket-name

# Route 53 Record
terraform import aws_route53_record.myrecord "Z4KAPRWWNC7JR_dev.example.com_NS"

Block Syntax

tfstate 操作の多くを実行できる。Planで確認したり、レビューしたりすることが可能なので、こちらの利用を推奨

✅ import Block

v1.5.0 から導入されたブロック。v1.7.0 からfor_eachが導入されたので、大量のリソースを一気に取り込むことが可能になった。

importコマンドと同様、公式ドキュメントを参考に適切なidを指定すること。

import {
  to = aws_instance.this
  id = "i-12345678"
}

✅ moved Block

v1.1.0 から導入されたブロック。リファクタリングでお世話になる。大量のmoved blockを作成しないといけない場合は生成AIを活用したりすると一気に作成できる。

moved {
  from = aws_instance.before
  to   = aws_instance.after
}

✅ removed Block

v1.7.0 から導入されたブロック。

importやmoveの構文とは少し異なり、lifecycledestroy = falseを入れる必要がある。lifecycleを入れない場合やdestroy = trueの場合はリソース自体が削除されるので、そもそもremoved Block を使う必要がなくなる。

removed {
  from = aws_instance.this
  lifecycle {
    destroy = false
  }
}

ユースケース

Block Syntax ではtfstate の操作を行うのが難しいユースケースについて紹介します。

1️⃣ 実行単位を分けたい

実行単位が大きくなってきて分割したい場合、tfstate も分割する必要があります。

複数のtfstate を利用するため、Block Syntax ではなくCLI でtfstate を操作します。

移行元のディレクトリにて

# まずは現状確認(差分0が望ましい)
terraform plan

# バックアップ(backup.tfstate)を取得
terraform state pull > backup.tfstate

# 移行したいリソースをに移動(mv.state)
terraform state mv -state-out=mv.tfstate module.xxx module.xxx

# 移行したいリソースがdestroyされるかどうかを確認
terraform plan

上記操作後、mv.tfstate を移行先のディレクトリに移動する。

移行先のディレクトリにて

# まずは現状確認(差分が出るはず)
terraform plan

# 先ほど作成したmv.tfstateを管理主体にする
terraform state push mv.tfstate

# 差分が出ないことを確認
terraform plan

上記操作後、mv.tfstateを削除する。

2️⃣ 既に存在する別のtfstateにリソースを追加したい

こちらのユースケースも複数のtfstate を利用するため、Block Syntax ではなくCLI でtfstate を操作します。

移行元のディレクトリにて

# out.tfstateにaws_instance.thisリソースを移行させる
# そのとき、元のtfstateからaws_instance.thisリソースが消える
terraform state mv -state-out=out.tfstate aws_instance.this aws_instance.this

出力したout.tfstate を移行先のディレクトリに移動させる。

移行先のディレクトリにて

# out.tfstate にあるaws_instance.this の情報を in.tfstate に移行する
terraform state mv -state=out.tfstate -state-out=in.tfstate aws_instance.this aws_instance.this

# in.tfstate をtfstate に上書きする
terraform state push in.tfstate

まとめ

直接tfstate を編集したり、実行結果が分からないままtfstate の操作を行ってしまうと実際のリソースが消えてしまうわけではありませんが、IaC を維持していくことが困難になります。そのため必ずバックアップを取得した上で、tfstate を安全に操作するようにしましょう。

5
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
9