
State Locking の仕組みを DynamoDB State Locking から S3 State Locking ヘ移行してみた
こんにちは!クラウド事業本部コンサルティング部のたかくに(@takakuni_)です。
少し前ですが、 Terraform v1.11 が GA となりました。
S3 の条件付き書き込みを利用した tfstate の排他制御(S3 State Locking)が挙げられます。
Terraform v1.11 以降から、 S3 State Locking の利用が推奨され、今まで使ってきた DynamoDB ベースの State Locking は非推奨になりました。
また、今後のマイナーバージョンのアップデートで使えなくなる旨も予告されています。
Locking can be enabled via S3 or DynamoDB. However, DynamoDB-based locking is deprecated and will be removed in a future minor version. To support migration from older versions of Terraform that only support DynamoDB-based locking, the S3 and DynamoDB arguments can be configured simultaneously.
そこで今回は DynamoDB State Locking から、S3 State Locking への移行を行いたいと思います。
やってみる
前提条件
まずは前提条件の整理です。
Terraform のバージョンは v1.11.3 まで引き上げており、非常にシンプルなファイル構成を想定します。
takakuni.shinnosuke@HL01556 state-lock-migrate % terraform version
Terraform v1.11.3
on darwin_arm64
+ provider registry.terraform.io/hashicorp/aws v5.92.0
takakuni.shinnosuke@HL01556 state-lock-migrate % tree .
.
├── backend.tf
├── providers.tf
└── vpc.tf
以下のようにリソースはデプロイ済みで、tfstate にてリソースが管理されている状況を想定します。
takakuni.shinnosuke@HL01556 state-lock-migrate % terraform state list
aws_vpc.this
takakuni.shinnosuke@HL01556 state-lock-migrate % terraform state show aws_vpc.this
# aws_vpc.this:
resource "aws_vpc" "this" {
arn = "arn:aws:ec2:ap-northeast-1:123456789012:vpc/vpc-0088770818f7b0316"
assign_generated_ipv6_cidr_block = false
cidr_block = "10.0.0.0/16"
default_network_acl_id = "acl-01dd4d4a3525456e7"
default_route_table_id = "rtb-03a1c6ad4f2e77772"
default_security_group_id = "sg-0d643c5de70109383"
dhcp_options_id = "dopt-03c00cf53d618e49b"
enable_dns_hostnames = false
enable_dns_support = true
enable_network_address_usage_metrics = false
id = "vpc-0088770818f7b0316"
instance_tenancy = "default"
ipv6_association_id = null
ipv6_cidr_block = null
ipv6_cidr_block_network_border_group = null
ipv6_ipam_pool_id = null
ipv6_netmask_length = 0
main_route_table_id = "rtb-03a1c6ad4f2e77772"
owner_id = "123456789012"
tags = {
"Name" = "vpc-terraform"
}
tags_all = {
"Name" = "vpc-terraform"
}
}
AWS Provider のバージョンは 5.92.0
を利用している状態とします。
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "5.92.0"
}
}
}
provider "aws" {
# Configuration options
region = "ap-northeast-1"
}
backend.tf
の内容は次の通りで、 DynamoDB State Locking を利用している状況からスタートです。
terraform {
backend "s3" {
bucket = "tfstate-123456789012"
key = "terraform.tfstate"
dynamodb_table = "tfstate-lock-table"
region = "ap-northeast-1"
}
}
権限の確認
まずは Backend リソースを操作する IAM の権限を確認します。
S3 State Locking は、tfstate を保管する S3 バケットの同階層に key名.tflock
といったオブジェクトを作成します。
たとえば、 backend "s3" の key 名が "terraform.tfstate" であれば、 terraform.tfstate.tflock
、 "hoge.tfstate" であれば hoge.tfstate.tflock
となります。
この辺りの権限に最小に絞っている場合は、以下のドキュメントにしたがって操作権限を見直しましょう。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::mybucket",
"Condition": {
"StringEquals": {
"s3:prefix": "mybucket/path/to/my/key"
}
}
},
{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:PutObject"],
"Resource": [
"arn:aws:s3:::mybucket/path/to/my/key"
]
},
{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
"Resource": [
"arn:aws:s3:::mybucket/path/to/my/key.tflock"
]
}
]
}
use_lockfile を指定
内容重複しますが、移行のために DynamoDB State Locking と S3 State Locking は共存できます。
Locking can be enabled via S3 or DynamoDB. However, DynamoDB-based locking is deprecated and will be removed in a future minor version. To support migration from older versions of Terraform that only support DynamoDB-based locking, the S3 and DynamoDB arguments can be configured simultaneously.
そのため、まずは backend.tf
に use_lockfile を記述します。
terraform {
backend "s3" {
bucket = "tfstate-123456789012"
key = "terraform.tfstate"
dynamodb_table = "tfstate-lock-table"
region = "ap-northeast-1"
+ use_lockfile = true
}
}
terraform init -reconfigure
で backend の初期化を行います。(tfstate の内容が消えるとかではないです)
takakuni.shinnosuke@HL01556 state-lock-migrate % terraform init -reconfigure
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.92.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 -reconfigure
を行わず、 terraform plan
を行うと、次のように怒られます。
takakuni.shinnosuke@HL01556 state-lock-migrate % terraform plan
╷
│ Error: Backend initialization required: please run "terraform init"
│
│ Reason: Backend configuration block has changed
│
│ The "backend" is the interface that Terraform uses to store state,
│ perform operations, etc. If this message is showing up, it means that the
│ Terraform configuration you're using is using a custom configuration for
│ the Terraform backend.
│
│ Changes to backend configurations require reinitialization. This allows
│ Terraform to set up the new configuration, copy existing state, etc. Please run
│ "terraform init" with either the "-reconfigure" or "-migrate-state" flags to
│ use the current configuration.
│
│ If the change reason above is incorrect, please verify your configuration
│ hasn't changed and try again. At this point, no changes to your existing
│ configuration or state have been made.
terraform apply
を行います。 No changes.
で変化なしですね。
takakuni.shinnosuke@HL01556 state-lock-migrate % terraform apply
aws_vpc.this: Refreshing state... [id=vpc-0088770818f7b0316]
No changes. Your infrastructure matches the configuration.
Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
S3 バケットの中身を見てみましょう。オブジェクト数が 1 のままですね。 terraform.tfstate.tflock
はどこにあるのでしょうか。
バージョニングを有効にしているバケットのため、バージョンの表示
をクリックすると確認できました。
どうやらこのファイルは排他制御(terraform plan や terraform apply)が終われば、都度削除されるようです。
(そのために IAM ポリシーに DeleteObject を付与しているってわけですね。)
dynamodb_table を削除
dynamodb_table の行を削除します。
terraform {
backend "s3" {
bucket = "tfstate-123456789012"
key = "terraform.tfstate"
- dynamodb_table = "tfstate-lock-table"
region = "ap-northeast-1"
use_lockfile = true
}
}
同じく terraform init -reconfigure
で Backend の初期化を行います。
takakuni.shinnosuke@HL01556 state-lock-migrate % terraform init -reconfigure
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.92.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 apply
で No changes.
を確認します。
takakuni.shinnosuke@HL01556 state-lock-migrate % terraform apply
aws_vpc.this: Refreshing state... [id=vpc-0088770818f7b0316]
No changes. Your infrastructure matches the configuration.
Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
オブジェクト数を確認すると、先ほどの terraform apply
分が換算されていますね。
まとめ
以上、「State Locking の仕組みを DynamoDB State Locking から S3 State Locking ヘ移行してみた」でした。
そこまで難易度の高い作業ではないですが、事前に作業時間を調整しておくとよさそうです。
このブログがどなたかの参考になれば幸いです。
クラウド事業本部コンサルティング部のたかくに(@takakuni_)でした!