TerraformのStateファイルどこに置くの問題、ちゃんと整理してみた件
どうも、拓田です。
TerraformでAWSを構築していて、GitHub Actionsで自動化しようとしたら「リソースが既に存在する」エラーが連発しました。
原因はstateファイルの管理ができていなかったことで、その過程でstateファイルの保存先について色々調べたのでまとめます。
そもそもstateファイルって何?
Terraformは「今どんなリソースが作られているか」を記録したファイルを持っています。
それが stateファイル(terraform.tfstate) です。
terraform apply を実行
↓
AWSにVPC・EC2・RDSが作られる
↓
stateファイルに「これを作った」と記録される
↓
次回 terraform apply 時に「何が変わったか」を比較して差分だけ更新する
このstateファイルをどこに保存するかが backend の設定です。
stateファイルの保存先の種類
| 保存先 | 向いている環境 |
|---|---|
| ローカル(デフォルト) | 個人開発のみ。チームでは使えない |
| S3(AWS) | AWSメインのチーム開発 |
| Azure Blob Storage | Azureメインのチーム開発 |
| Google Cloud Storage | GCPメインのチーム開発 |
| HCP Terraform | クラウド問わず使えるHashiCorp公式サービス |
| GitLab | GitLabを使っているチーム向け |
デフォルトはローカル保存ですが、チーム開発では必ず外部に保存する設定が必要です。
失敗談:S3 backendを後から追加したらハマった
GitHub Actionsで terraform apply を実行したところ、2回目以降にこんなエラーが出ました。
Error: DBSubnetGroupAlreadyExists:
The DB subnet group 'terraform-db-subnet-group' already exists.
原因: stateファイルがGitHub Actionsの実行環境に保存されていたため、次回実行時には消えてしまっていた。Terraformが「何も作っていない」と思い込み、既存リソースを再作成しようとしてエラー。
S3 backendはmain.tfを作成する前に必ず設定してください。
後から追加すると、部分的に作られたリソースとstateの不整合が起きて手動削除が必要になります。
正しい順番はこちらです。
① S3バケットを作成する
↓
② main.tfにbackend設定を追加する ← ここが先!
↓
③ AWSリソースを定義する
↓
④ terraform apply
AWSでのベストプラクティス:S3 + DynamoDB(※拓田調べ)
AWSメインのチームには S3 + DynamoDB の組み合わせが定番です。(※拓田調べ)
S3だけでは足りない理由:stateのロック問題
複数人が同時に terraform apply を実行するとstateファイルが壊れる可能性があります。
これを防ぐのが DynamoDBによるstateロック です。
Aさんが terraform apply を実行
↓
DynamoDBにロックを記録(「今Aさんが使用中」)
↓
Bさんが terraform apply を実行しようとする
↓
「ロック中です」とエラーになり、待機または中断
↓
Aさんの apply 完了後、ロック解除
↓
Bさんが実行できるようになる
設定方法
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
backend "s3" {
bucket = "terraform-state-(バケット名)"
key = "terraform.tfstate"
region = "ap-northeast-1"
dynamodb_table = "terraform-lock" # ← ロック用テーブル
}
}
S3バケットの設定
| 項目 | 値 |
|---|---|
| バージョニング | 有効にする(stateの変更履歴を残せる) |
| パブリックアクセス | すべてブロック |
| 暗号化 | SSE-S3 |
HCP Terraformとは
HashiCorpが提供するTerraformのマネージドサービスです。
stateの管理からTerraformの実行まで、クラウドで一括管理できます。
主な機能
| 機能 | 内容 |
|---|---|
| stateファイルの管理 | 保存・バージョン管理・ロック(自動) |
| GitHubとの連携 | pushをトリガーにTerraformを自動実行 |
| 実行ログの管理 | init/plan/applyの実行履歴をWeb UIで確認 |
| planの承認フロー | applyの前に人間が内容を確認してOKを出せる |
| 変数・シークレット管理 | GitHub Secretsの代わりにHCP側で管理できる |
| 通知 | Slack・メールへの実行結果通知 |
| アクセス制御 | チームメンバーごとに権限を設定できる |
特に重要:planの承認フロー
本番環境での運用で特に強力な機能です。
GitHubにpush
↓
HCP TerraformがPlanを実行(何が変わるか表示)
↓
担当者がWeb画面で内容を確認・承認 ← 人間のレビューを挟める
↓
Applyが実行されてAWSに反映
GitHub Actionsだと -auto-approve で自動実行になりがちですが、
HCP Terraformでは意図しないリソース削除を防ぐ承認ステップを挟めます。
GitHub + HCP Terraform + AWSの連携構成
GitHub(コード管理)
↓ pushをトリガー
HCP Terraform(Terraformの実行・state管理)
↓ OIDCで認証
AWS(インフラの作成先)
各サービスの役割
| サービス | 役割 |
|---|---|
| GitHub | Terraformコードを管理・変更のトリガー |
| HCP Terraform | Terraformを実行・stateファイルを管理 |
| AWS | 実際にリソースが作られる場所 |
S3 + DynamoDB vs HCP Terraform
| S3 + DynamoDB | HCP Terraform | |
|---|---|---|
| stateの保存 | S3 | HCP側が管理 |
| ロック | DynamoDB | 自動で管理 |
| Web UI | なし | あり(実行履歴が見られる) |
| planの承認フロー | 自前で実装が必要 | 標準機能 |
| クラウド依存 | AWSに依存 | クラウド問わず使える |
| 料金 | S3・DynamoDBの従量課金 | 小規模なら無料 |
| セットアップの手軽さ | やや手間 | 比較的シンプル |
状況別おすすめ構成
| 状況 | おすすめ |
|---|---|
| 個人・ローカル開発 | ローカル(デフォルト) |
| AWSオンリーのチーム | GitHub Actions + OIDC + S3 + DynamoDB |
| マルチクラウド・大規模チーム | GitHub + HCP Terraform + AWS |
| 書籍で学習したい | HCP Terraform(書籍はこちらが多い) |
まとめ
- stateファイルはTerraformが「何を作ったか」を記録するファイル
- チーム開発では必ずS3などの外部に保存する
- AWSなら S3 + DynamoDB がベストプラクティス(DynamoDBはロック用)
- S3 backendの設定はmain.tf作成前に必ずやること(後からだとハマる)
- より高機能な管理がしたければ HCP Terraform が選択肢
- planの承認フローは本番運用で特に重要
stateファイルの管理をちゃんとするだけで、チーム開発での事故がぐっと減ります。