TerraformのState(tfstate)完全解説|チーム開発で絶対に知っておくべき仕組み
Terraformを使い始めた人が最初に「よくわからない」と感じるのが State(状態管理) です
しかし、ここを理解しないとチーム開発でとんでもない事故が起きます。逆に理解できれば、Terraformへの不安がほぼなくなります。しっかり押さえましょう。
Stateとは何か
Terraformはインフラの「現在の状態」をファイルで管理しています。これが tfstate(terraform.tfstate) ファイルです。
// terraform.tfstate の中身(例)
{
"version": 4,
"terraform_version": "1.9.8",
"resources": [
{
"type": "aws_s3_bucket",
"name": "my_bucket",
"instances": [
{
"attributes": {
"id": "my-example-bucket",
"bucket": "my-example-bucket",
"region": "ap-northeast-1",
...
}
}
]
}
]
}Terraformは terraform apply を実行するたびに、この「前回の状態(tfstate)」と「コードの定義」を比較して、差分だけを実行します。
コード(.tf) tfstate(前回の状態)
↓ ↓
差分を計算
↓
実際のAWSに適用なぜStateが必要なのか
「AWSに直接問い合わせればいいのでは?」と思うかもしれません。
しかし問題があります。
① リソースのマッピングが複雑 TerraformのコードIDとAWS側のリソースIDは一致しません。Stateがその対応表になっています。
② パフォーマンス 毎回すべてのAWSリソースに問い合わせると、数百・数千のリソースがある環境では実行に何分もかかります。
③ 依存関係の追跡 どのリソースがどのリソースに依存しているかをStateが記録しています。
ローカルStateの問題点
terraform apply を実行すると、デフォルトでは terraform.tfstate がローカルに作成されます。
これには大きな問題があります。
【ローカルStateの問題】
開発者A: terraform apply → tfstateがAのPCに保存
開発者B: terraform apply → BのPCにあるtfstateは古い!
↓
二重実行で環境が壊れるまた、tfstateにはAWSリソースの情報(場合によってはパスワードなど機密情報)が入るため、Gitにコミットすることもできません。
Remote State:S3でStateを管理する
チーム開発では Remote State を使います。tfstateをS3に保存して全員で共有する方法です。
S3バケットとDynamoDBテーブルを作る
まずS3バケット(tfstate保存用)とDynamoDBテーブル(ロック用)を作成します。
# bootstrap/main.tf
# このリソース自体はコンソールで作るか、一度だけ別途applyする
resource "aws_s3_bucket" "tfstate" {
bucket = "my-tfstate-bucket-xxxxxxx" # 世界でユニークな名前
}
resource "aws_s3_bucket_versioning" "tfstate" {
bucket = aws_s3_bucket.tfstate.id
versioning_configuration {
status = "Enabled" # バージョニングは必須!
}
}
resource "aws_s3_bucket_server_side_encryption_configuration" "tfstate" {
bucket = aws_s3_bucket.tfstate.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
# 状態ロック用のDynamoDBテーブル
resource "aws_dynamodb_table" "tfstate_lock" {
name = "terraform-state-lock"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute {
name = "LockID"
type = "S"
}
}backendの設定
terraform {} ブロックに backend "s3" を追加します。
terraform {
required_version = ">= 1.9.0"
backend "s3" {
bucket = "my-tfstate-bucket-xxxxxxx"
key = "production/terraform.tfstate" # 保存先のパス
region = "ap-northeast-1"
dynamodb_table = "terraform-state-lock" # ロック用テーブル
encrypt = true
}
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}terraform init を実行するとS3に切り替わります。
State Lockとは
DynamoDBを使った State Lock は非常に重要な仕組みです。
複数人が同時に terraform apply を実行すると、tfstateが壊れます。State Lockはそれを防ぎます。
開発者A: terraform apply開始 → DynamoDBにロック取得
開発者B: terraform apply開始 → ロック中!待機 or エラー
開発者A: apply完了 → ロック解除
開発者B: ロック取得 → apply開始Stateに関するコマンド
state list:管理中のリソース一覧
terraform state list
# 出力例
aws_instance.web
aws_s3_bucket.my_bucket
aws_vpc.mainstate show:リソースの詳細を確認
terraform state show aws_s3_bucket.my_bucketstate mv:リソースの名前変更
コード内でリソース名を変えたとき、そのままだと「削除して再作成」になってしまいます。state mv を使うと再作成せず名前だけ変更できます。
# コード上で aws_s3_bucket.old → aws_s3_bucket.new に変えた場合
terraform state mv aws_s3_bucket.old aws_s3_bucket.newstate rm:管理から外す
Terraformの管理から外したいリソース(削除はしない)がある場合:
terraform state rm aws_s3_bucket.my_bucketterraform import:既存リソースをState管理下に取り込む
コンソールで作ったリソースをTerraformで管理し始めたい場合は import を使います。
# Terraform 1.5以降はimportブロックで書ける
import {
to = aws_s3_bucket.existing
id = "existing-bucket-name"
}または古い方法:
terraform import aws_s3_bucket.existing existing-bucket-nametfstateの注意点まとめ
✅ DO
- S3 + DynamoDBでRemote State管理する
- S3バケットのバージョニングを有効にする(誤操作からの復元用)
- S3バケットの暗号化を有効にする
❌ DON'T
- tfstateをGitにコミットしない(機密情報が含まれる)
- tfstateを手動で編集しない
- ローカルのtfstateをチームで使わないまとめ
tfstateはTerraformがインフラの「現在の状態」を記録するファイル
ローカル保存はチーム開発では使えない
S3 + DynamoDBでRemote State管理するのがベストプラクティス
State Lockで同時実行を防ぐ
terraform state コマンドでStateを操作できる
次の記事ではTerraformの ディレクトリ構成 のベストプラクティスを解説します。小規模プロジェクトから大規模まで、どう整理すればいいかを具体的に見ていきます。
いいなと思ったら応援しよう!
応援をぜひよろしくお願いします🔥
いただいたチップでより素晴らしい記事を発信していけるよう精進してまいります!