目次
はじめに
こんにちは、ディーネットの牛山です。
今回は、Terraformでデプロイした時にインフラストラクチャ状態を記録するステートファイル管理について解説します。
Terraformの管理を複数人で行いたい場合、インフラストラクチャ状態を管理しているステートファイルを同時に変更されてしまうと、不整合が起きてしまう為、ステートロックという仕組みが提供されていますので今回はこれを使用します。
複数人でステート管理を行う場合、AWSでステート管理をS3とDynamoDBで管理を行うことが通例になっていると思いますが、S3のみで管理することが可能になりましたのでこちらを試してみたという内容になります。
前提条件
- Terraform S3のみによる状態管理機能は、Terraform バージョン
1.11.0
で提供されますので使用する際はご注意ください。
動作確認する内容
状態管理するS3バケットと普通にリソース作成として別S3バケットを作成し、複数人で作成したリソース(S3バケット)の変更等が行えないことを確認してみます。
下準備
tfstateファイルを管理するS3バケットを事前に作成する必要があります。
cloudformationテンプレートを使用し、rainコマンドで作成します。
AWSTemplateFormatVersion: 2010-09-09
Description: 'S3バケット作成とバージョニング有効化のためのCloudFormationテンプレート'
Parameters:
DateSuffix:
Type: String
Description: 'S3バケット名に付加する日付文字列(例:2025042901)'
Resources:
TerraformStateBucket:
Type: 'AWS::S3::Bucket'
Properties:
BucketName: !Sub 'terraform-state-${DateSuffix}'
VersioningConfiguration:
Status: Enabled
Outputs:
S3BucketName:
Description: 'S3バケットの名前'
Value: !Ref TerraformStateBucket
S3BucketArn:
Description: 'S3バケットのARN'
Value: !GetAtt TerraformStateBucket.Arn
rainコマンドを使用し、AWS環境へ適用します。
rainコマンドは、CloudFormationテンプレートの管理を便利にするコマンドツールになります。
S3バージョニングを有効化した、S3バケット名 terraform-state-{可変} で作成されます。
rain deploy backend.cf.yaml
Rain needs to create an S3 bucket called 'rain-artifacts-674036551124-ap-northeast-1'. Continue? (Y/n) y
Enter a value for parameter 'DateSuffix' "S3バケット名に付加する日付文字列(例:2025042901)": 2025042901
CloudFormation will make the following changes:
Stack backend-cf:
+ AWS::S3::Bucket TerraformStateBucket
Do you wish to continue? (Y/n) y
Deploying template 'backend.cf.yaml' as stack 'backend-cf' in ap-northeast-1.
Stack backend-cf: CREATE_COMPLETE
Outputs:
S3BucketArn: arn:aws:s3:::terraform-state-2025042901 # S3バケットのARN
S3BucketName: terraform-state-2025042901 # S3バケット名
Successfully deployed backend-cf
次に、Terraformプロジェクトに、tfstateをS3で管理することを知らせ、terraform initで初期化する必要があります。
backend.tf等の任意名で次のコードを作成します。
terraform {
backend "s3" {
bucket = "terraform-state-2025042901"
key = "terraform.tfstate"
region = "ap-northeast-1"
use_lockfile = true
}
}
use_lockfile = trueにすることで、S3のみで状態ロック管理が行えるようになります。
bucket名は、先ほどrainコマンドで作成したS3バケット名を指定するようにします。
次に、terraformの初期化を行う必要がありますので、terraform initコマンドを実行します。
terraform init
Initializing the backend...
Successfully configured the backend "s3"! Terraform will automatically
use this backend unless the backend configuration changes.
Initializing provider plugins...
- Reusing previous version of hashicorp/aws from the dependency lock file
- Using previously-installed hashicorp/aws v5.89.0
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 initの出力結果)
バックエンド 「s3」 の設定に成功しました!バックエンドの設定が変更されない限り
バックエンドの設定が変更されない限り、自動的にこのバックエンドを使用します。
ここまででS3でtfstate管理準備が整いました。
実際に動作確認用S3バケットを作成し、他の人から変更できないことを確認していきます。
動作確認用S3バケット作成
プロジェクトに、s3.tf等任意名で次のS3バケット作成指示を記載します。
resource "aws_s3_bucket" "example" {
bucket = "example-2025042901"
}
terraform planを実行し、適用前の計画を作成します。
terraform plan
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# aws_s3_bucket.example will be created
+ resource "aws_s3_bucket" "example" {
・・・
}
Plan: 1 to add, 0 to change, 0 to destroy.
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply" now.
terraform applyを実行します。
Enter a value: の時点で一旦、なにも入力せず止めておきます。
この時点で、S3バケットに対してロックファイルが作成されます。
terraform apply
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# aws_s3_bucket.example will be created
}
Plan: 1 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value:
この状態のS3バケット(状態管理)以下です。
aws s3 ls s3://terraform-state-2025042901
2025-04-29 21:56:00 181 terraform.tfstate
2025-04-29 22:03:21 230 terraform.tfstate.tflock
他ユーザのターミナルからterraform planを実行すると、「エラー: 状態ロック取得エラー」となり、planまたはapplyが実行できない旨のメッセージが出るようになり、期待した動作になっていることを確認できました。
terraform plan
╷
│ Error: Error acquiring the state lock
│
│ Error message: operation error S3: PutObject, https response error StatusCode: 412, RequestID: NEXEYMZE29GQ8W4R, HostID:
│ 6Jaz/QGL2kHNuyuMVbW2BLqOEuJ/RAQeSmZqstGSw4P+1L025F04CKnBxJn4GyibuejQt4F6giifbQZs9XxEXcbeDXeY6RIjrbSsF33qSmE=, api error PreconditionFailed: At least one of the pre-conditions you
│ specified did not hold
│ Lock Info:
│ ID: 3eed455d-cbfb-a148-0d00-9463e0313a9c
│ Path: terraform-state-2025042901/terraform.tfstate
│ Operation: OperationTypeApply
│ Who: {デバイス名}\{ユーザ名}@{デバイス名}
│ Version: 1.11.0
│ Created: 2025-04-29 13:03:19.8206215 +0000 UTC
│ Info:
│
│
│ Terraform acquires a state lock to protect the state from being written
│ by multiple users at the same time. Please resolve the issue above and try
│ again. For most commands, you can disable locking with the "-lock=false"
│ flag, but this is not recommended.
まとめ
操作中ロックファイルが作成され、変更適用中に、他の人が変更を掛けようとする場合、エラーとなることが確認でき、誰が変更適用中かまで分かるので便利な機能ですね。

プロフィール
AWSの設計・構築をメインにおこなっています。
運用・保守をおこなう部署におりましたが、最近、アーキテクト課に異動しました。
日々精進しております。
LINK
クラウドベリージャム:プロフィールページ