0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Terraform State管理

Posted at

Terraform State管理のベストプラクティス:チーム開発で破綻しないための戦略と実践テクニック

Terraform を実務で使うインフラエンジニア / SRE 向けに、運用の要である State 管理を深掘り解説。State は「コードで定義したインフラ」と「実際のリソース状態」を結びつける 唯一の信頼できる情報源。その扱い方がスケーラビリティ、チーム効率、安定性を左右する。

本記事のゴール

  • リモート State とロックで同時実行の破綻を防ぐ
  • State 分離で巨大 Stateを回避し、速度と保守性を両立
  • moved / removed宣言的に安全なリファクタリングを行う

目次


1. リモート State と排他ロック

ローカル State は分岐を招きやすく、チーム開発では高確率で破綻する。共有場所に State を置く リモートバックエンドを採用し、加えて 排他ロックで同時実行を制御する。

ローカル管理が招く分岐の例

推奨構成(S3 + DynamoDB Lock)

# versions.tf or backend.tf
terraform {
  backend "s3" {
    bucket         = "your-tfstate-bucket-name"        # State を保管する S3 バケット
    key            = "path/to/project/terraform.tfstate" # バケット内のパス
    region         = "ap-northeast-1"
    dynamodb_table = "your-terraform-lock-table"        # 排他ロック用テーブル
  }
}

実行フロー
terraform plan/apply 開始 → DynamoDB にロック取得 → 他の実行は待機 → 完了で解放

効果

  • 単一の最新 State を全員で共有
  • 同時書き込みによる破損を防止
  • 個人 PC 依存からの脱却

2. 巨大 State を避ける分離戦略

State が肥大化すると plan/apply が遅いstate 操作が複雑ミスの影響範囲が拡大。分離で回避する。

戦略A: ワークスペースで環境分離

単一コードで複数環境(dev/stg/prod)を管理。terraform.workspace で動的切替。

# main.tf
locals {
  instance_settings = {
    stg = { type = "t3.medium", ami = "ami-stg-xxxxxxxxxxxx" }
    prod = { type = "r5.large",  ami = "ami-prod-yyyyyyyyyyyy" }
  }
}

resource "aws_instance" "app_server" {
  instance_type = local.instance_settings[terraform.workspace].type
  ami           = local.instance_settings[terraform.workspace].ami
  tags = { Name = "${terraform.workspace}-app-server", Env = terraform.workspace }
}
  • 長所: コード重複が少ない。環境間でほぼ同一構成のとき効率的
  • 短所: 環境差分が大きいと条件分岐が増え可読性が低下

戦略B: ディレクトリ分離

環境・コンポーネントごとにディレクトリを分ける。State も独立。

.
├── envs
│   ├── dev/
│   ├── stg/
│   └── prod/
└── modules/
  • 長所: 独立性が高く明快。影響範囲が限定される
  • 短所: 共通化しないと重複が増える。環境差異が広がりやすい

分離の判断軸

  • 依存関係: 疎結合なら分ける(例: VPC と ECS サービス)
  • ライフサイクル/変更頻度: 低頻度(VPC)と高頻度(ECS, ALB, Lambda)は分ける

3. コードによる State 操作: moved / removed

手作業の terraform state mv/rm は属人化しやすい。宣言的ブロックで Git レビュー可能な形にする。

moved で安全にアドレス変更

countfor_each などのリファクタで再作成を防ぐ。

変更前(count)

# main.tf (before)
locals { bucket_name = ["my", "your", "their"] }

resource "aws_s3_bucket" "sample_bucket" {
  count  = length(local.bucket_name)
  bucket = "${local.bucket_name[count.index]}-bucket"
}
# State: aws_s3_bucket.sample_bucket[0],[1],[2]

変更後(for_each + moved)

# main.tf (after)
locals { bucket_name = ["my", "your", "their"] }

resource "aws_s3_bucket" "sample_bucket" {
  for_each = toset(local.bucket_name)
  bucket   = "${each.value}-bucket"
}

moved { from = aws_s3_bucket.sample_bucket[0] to = aws_s3_bucket.sample_bucket["my"] }
moved { from = aws_s3_bucket.sample_bucket[1] to = aws_s3_bucket.sample_bucket["your"] }
moved { from = aws_s3_bucket.sample_bucket[2] to = aws_s3_bucket.sample_bucket["their"] }
  • 効果: 実リソースには触れず State アドレスのみ移行
  • メリット: Git 履歴で意図が追跡可能。レビュー可能

removed で管理対象から安全に外す

実体を消さずに Terraform 管理から外す。

# resource "aws_iam_role" "legacy_role" { ... }  # ← これを削除しつつ

removed {
  from = aws_iam_role.legacy_role
  lifecycle {
    destroy = false   # 実リソースは削除しない
  }
}

ユースケース

  • State A から State B へ移管したい
  • いったん import してコード化し、その後非管理に戻す

まとめ

  • S3 + DynamoDB Lock のリモート State は必須。共有と同時実行制御で破綻を防ぐ
  • 分離設計は依存関係とライフサイクルで決める。巨大 State を回避し plan/apply を高速化
  • moved / removed で State 変更を宣言的に。安全で再現性の高いリファクタリングを実現

適切な State 管理は設計思想。ヒューマンエラーを減らし、変更意図を可視化し、プロジェクトのスケールを可能にする。ここで示した戦略を適用すれば、チーム開発に耐える堅牢な IaC を実現できる。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?