以下の内容はhttps://kakakakakku.hatenablog.com/entry/2025/01/17/012216より取得しました。


Terraform S3 Backend でステートロックのための DynamoDB が不要になる use_lockfile = true

Terraform v1.10.0 で導入された S3 Backend の use_lockfile オプションを使うと,Amazon S3 バケットで tfstate を管理しつつ,Amazon S3 のネイティブ機能 (conditional writes) でステートロックも実現できる👌今までステートロックのために使っていた Amazon DynamoDB が不要になるというメリットがある❗️

github.com

Terraform v1.10.0 は2024年11月にリリースされて,use_lockfile オプション自体もまだ Experimental(実験的)ではあるけど,既に use_lockfile オプションが Experimental ではなくなって,今度は逆に Amazon DynamoDB を使ったステートロックの仕組みが Deprecated(非推奨)になるというプルリクエストが merge されている📝

github.com

そして Terraform v1.11.0-beta1 のリリースノートに S3 native state locking is now generally available. と載っていた.よって,Terraform v1.11.0 からは use_lockfile オプションを使うことが一般的になりそう.

github.com

最近 S3 Backend の use_lockfile オプションを紹介する機会があって,デモ環境を作ったため,簡単にまとめておこうと思う👌

use_lockfile オプションを試す

Amazon S3 バケットを作る

まず,tfstate を管理する Amazon S3 バケットを作る🗑️

$ aws s3api create-bucket \
    --bucket kakakakakku-sandbox-tfstates \
    --create-bucket-configuration LocationConstraint=ap-northeast-1
$ aws s3api put-bucket-versioning \
    --bucket kakakakakku-sandbox-tfstates \
    --versioning-configuration Status=Enabled

ドキュメントに警告として載っている通り,Amazon S3 バケットのバージョニング機能も有効化しておく👌あと今回は割愛しているけど,ライフサイクルポリシーで古くなったバージョニングを消しておくと良いと思う.

Warning! It is highly recommended that you enable Bucket Versioning on the S3 bucket to allow for state recovery in the case of accidental deletions and human error.

developer.hashicorp.com

👾 backend.tf

backend.tf は以下のようにした.ポイントは S3 Backend で use_lockfile = true を設定しているところ💡

terraform {
  backend "s3" {
    region       = "ap-northeast-1"
    bucket       = "kakakakakku-sandbox-tfstates"
    key          = "terraform.tfstate"
    use_lockfile = true
  }
}

👾 main.tf

main.tf は何でも良くて,今回は Amazon CloudWatch ロググループを作る📝

resource "aws_cloudwatch_log_group" "main" {
  name = "sandbox-use-lockfile"
}

init / plan / apply(1回目)

普段通りに init / plan を実行する.

$ terraform init
Initializing the backend...

Successfully configured the backend "s3"! Terraform will automatically
use this backend unless the backend configuration changes.
(中略)
Terraform has been successfully initialized!

$ terraform plan
(中略)
Plan: 1 to add, 0 to change, 0 to destroy.

そして次に apply を実行して Enter a value を入力するときにステートロックを確認できる👌

$ terraform apply
(中略)
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: 

yes を入力せず Amazon S3 バケットを確認すると terraform.tfstate.tflock ファイルが保存されていた❗️(正確には plan 実行時にも terraform.tfstate.tflock ファイルは作られていて,バージョニングを確認するとわかる)

最後に yes を入力して apply を完了しておく.

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

すると今度は Amazon S3 バケットに terraform.tfstate ファイルが保存されて,terraform.tfstate.tflock ファイルは削除されていた👌

plan / apply(2回目)

今度はステートロックを確認する.Amazon CloudWatch Logs に retention_in_days = 7 を追加する.

resource "aws_cloudwatch_log_group" "main" {
  name              = "sandbox-use-lockfile"
  retention_in_days = 7
}

同じく plan / apply を実行して,Enter a value で止めておく🛑

$ terraform plan
Plan: 0 to add, 1 to change, 0 to destroy.

$ terraform apply
(中略)
Plan: 0 to add, 1 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:

そして別のターミナルから plan を実行すると Error: Error acquiring the state lock というエラーが出てステートロックを確認できた👏 期待通り〜 \( 'ω')/

$ terraform plan
╷
│ Error: Error acquiring the state lock
│ 
│ Error message: operation error S3: PutObject, https response error StatusCode: 412, RequestID: AXHQ4SP42S1DE2XQ, HostID: Xf6uqAz2Oo+c2+QXKdrL0tzBi6GKHVFjCg6gz/WH9HXt/yZEm9f+82en89RHGRZzoWvQSxjCifQ=, api error PreconditionFailed: At least one of the
│ pre-conditions you specified did not hold
│ Lock Info:
│   ID:        41f52805-3896-a963-70e3-a4bc02de9ea8
│   Path:      kakakakakku-sandbox-tfstates/terraform.tfstate
│   Operation: OperationTypeApply
│   Who:       kakakakakku@MacBookAir.local
│   Version:   1.10.3
│   Created:   2025-01-12 01:48:20.240611 +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.
╵

さらにエラーを確認すると「ステータスコード 412」と「メッセージ PreconditionFailed」になっていて,Amazon S3 の conditional writes(条件付き書き込み)のレスポンスになっていることもわかる.

docs.aws.amazon.com

Amazon DynamoDB を使わずにステートロックを実現できた❗️

仕組み

ステートロックの仕組みとしては,2024年8月にリリースされた Amazon S3 の conditional writes(条件付き書き込み)を使っていて,terraform.tfstate.tflock ファイルを保存するときの条件として --if-none-match を指定している.よって,Amazon S3 バケットに既に terraform.tfstate.tflock ファイルが存在していたら保存に失敗して,競合を検知できるようになっている.

aws.amazon.com

実際の Terraform の実装だと internal/backend/remote-state/s3/client.go が参考になる📝

input := &s3.PutObjectInput{
    ContentType: aws.String("application/json"),
    Body:        bytes.NewReader(lockFileJson),
    Bucket:      aws.String(c.bucketName),
    Key:         aws.String(c.lockFilePath),
    IfNoneMatch: aws.String("*"),
}

まとめ

Terraform v1.10.0 で導入された S3 Backend の use_lockfile オプションを使うと,ステートロックのために使っていた Amazon DynamoDB が不要になるので覚えておこう👌

関連ドキュメント

developer.hashicorp.com




以上の内容はhttps://kakakakakku.hatenablog.com/entry/2025/01/17/012216より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14