TerraformでCloud Storageのバケット名を変更する際の罠
最近よくデータ基盤構築の仕事をしているため、TerraformでGCPをいじったりしています。今回はCloud Storageのバケット名を変更する際に罠にはまりやすいところを紹介します。もちろん、Cloud Storageだけでなく、他のサービスやAWSなどにも活用できそうな箇所があるではないかと思います。
経緯
下記のバケットを作って検証環境に反映した後、PRを出しました。
resource "google_storage_bucket" "my_bucket" {
name = "my-bucket"
storage_class = var.gcs_storage_class.coldline
project = var.project_id
location = var.gcs_location
force_destroy = false
uniform_bucket_level_access = true
retention_policy {
is_locked = true
retention_period = 30
}
lifecycle_rule {
condition {
age = 30
}
action {
type = "Delete"
}
}
}
チームメンバーのレビュー受けて、バケット名はmy-bucket
よりmy-bucket-hoge
の方が良いと言われたので、my-bucket
をmy-bucket-hoge
変更しterraform apply
したらエラーになりました。もちろんのことですが、最初はforce_destroy = false
に設定していて、バケット内オブジェクトが入っているので、強制変更はできません。
force_destroy - (Optional, Default: false) When deleting a bucket, this boolean option will delete all contained objects. If you try to delete a bucket that contains objects, Terraform will fail that run.
解決方法を二つ見つけました。
- バケット内のオブジェクトを消してから、再度
terraform apply
- バケットを丸ごと削除
特別な理由がない限り、1の方が断然便利です。何らかの理由でこの開発用のバケットを丸ごと削除しないといけない、あるいは(筆者のように)コンソールからバケットを消しちゃったといった場合は追加の対策が必要です。
バケットが消された際の対策
まず、terraform plan
を実行すると
Error: Error acquiring the state lock
Error message: resource temporarily unavailable
TerraformとGCPのstateが噛み合わないので、ロックがかけられます。
terraform force-unlock {you-lock-id}
を使って、ロックを解除できます。この操作はかなり危ないので、チームメンバーが直近作業したかを確認してからやったほうが良いでしょう。
再度terraform plan
を実行すると、Refreshing state...
に永遠に止まっているように見えます。公式ドキュメントを調べると、環境変数を設定して再度planするとより詳細なログが見れます。
export TF_LOG=TRACE
terraform plan
---[ RESPONSE ]--------------------------------------
HTTP/2.0 404 Not Found
Content-Length: 171
Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Type: application/json; charset=UTF-8
Date: Fri, 27 May 2022 01:12:48 GMT
Expires: Mon, 01 Jan 1990 00:00:00 GMT
Pragma: no-cache
Server: UploadServer
Vary: Origin
Vary: X-Origin
X-Guploader-Uploadid: xxxx
{
"error": {
"code": 404,
"message": "The specified bucket does not exist.",
"errors": [
{
"message": "The specified bucket does not exist.",
"domain": "global",
"reason": "notFound"
}
]
}
}
バケットがあるはずなのになかったぞというエラーメッセージが無限に出ています。理由としては、terraformのstateが古いままになっています。幸いなことにTerraformすでにterraform state rm
という古いstateを消す機能を提供してくれています。最初に作ったバケットのstateを下記コマンドで削除します。
terraform state rm module.storage.google_storage_bucket.my_bucket
もう一度terraform plan
を実行すると問題解決です。
Cloud Storage以外に、似たような事象が起きた際にも今回の経験を活用できそうですね。
それでは!
Discussion