我有一个现有的 S3 存储桶,我想向其中添加“文件夹”和 lifecycle_rules。
(我说“文件夹”是因为它们在客户端的表示方式就是这样的,因为它们是通过存储网关访问的。)
我可以创建文件夹,例如用于保存季度备份,例如:
resource "aws_s3_bucket_object" "quarterly" {
bucket = "${var.bucket_id}"
acl = "private"
key = "quarterly"
source = "/dev/null"
}
但如果我尝试添加生命周期规则,如下所示
resource "aws_s3_bucket" "quarterly" {
bucket = "${var.bucket_id}"
acl = "private"
lifecycle_rule {
id = "quarterly_retention"
prefix = "quarterly/"
enabled = true
tags {
"rule" = "quarterly"
}
expiration {
days = 92
}
}
}
当我执行 terraform apply 时出现错误。
* aws_s3_bucket.quarterly: Error creating S3 bucket: BucketAlreadyOwnedByYou: Your previous request to create the named bucket succeeded and you already own it.
status code: 409, request id: 702396A7D2FA28BA, host id: IJDA+vszRBYl4zmvW56dSnC2va2qpQXlfgeEL7X1QQHHv8eEaYKvSUCL0ZIj/VsdvQ2hkBLGjAY=
我想先创建存储桶,然后再添加文件夹和生命周期规则,而不是在创建时嵌入生命周期规则。
我是否遗漏了什么,或者我是否理解错了?
感谢您的帮助!
答案1
首先创建存储桶并逐步更新配置应该可以正常工作,最终结果是,如果您通过其他方式删除存储桶,Terraform 将使用所有规则重新创建它。
看起来您丢失了terraform.tfstate
文件,因此 Terraform 不知道它已经创建了您的存储桶,或者您首先在 Terraform 之外创建了存储桶,因此它尝试创建它但失败了。Terraform 需要“拥有”存储桶才能更新其配置,即生命周期规则。
您应该能够使用类似以下方法将现有存储桶导入到状态文件中
terraform import aws_s3_bucket.quarterly <your bucket ID>
参见底部https://www.terraform.io/docs/providers/aws/r/s3_bucket.html
运行 Terraform 应该会显示它仅更新生命周期规则。
答案2
按照@bodgit,该方法是将生命周期规则嵌入“aws_s3_bucket”资源中并重新运行“terraform apply”。
lifecycle_rule 子句可以添加到资源中(或从资源中删除),并应用于存储桶。
我一直希望将规则与存储桶创建分开,以便可以分别执行它们,但这样就可以了。
因此,我使用以下方式定义存储桶:
resource "aws_s3_bucket" "bucket" {
bucket = "${replace(var.tags["Name"],"/_/","-")}"
region = "${var.aws_region}"
tags = "${merge(var.tags, map("Name", "${replace(var.tags["Name"],"/_/","-")}"))}"
lifecycle_rule {
id = "quarterly_retention"
prefix = "quarterly/"
enabled = true
expiration {
days = 92
}
}
}
当我运行“terraform apply”时,将使用 1 条规则创建存储桶。
然后我编辑我的.tf 文件并添加第二个lifecycle_rule。
resource "aws_s3_bucket" "bucket" {
bucket = "${replace(var.tags["Name"],"/_/","-")}"
region = "${var.aws_region}"
tags = "${merge(var.tags, map("Name", "${replace(var.tags["Name"],"/_/","-")}"))}"
lifecycle_rule {
id = "quarterly_retention"
prefix = "quarterly/"
enabled = true
expiration {
days = 92
}
}
lifecycle_rule {
id = "permanent_retention"
enabled = true
prefix = "permanent/"
transition {
days = 1
storage_class = "GLACIER"
}
}
}
当我再次执行“terraform apply”时,存储桶已添加第二条规则。
如果我再次编辑规则,删除规则,并再次运行“应用”,规则就会消失。
如果我随后进行编辑,添加一条规则,并再次运行应用,那么该规则就在那里。
谢谢您的帮助!
答案3
目前,AWS Provider v3.27 不支持外部化 AWS 托管 S3 的存储桶配置,但允许使用以下方式为 S3 Outposts 进行外部化s3control_bucket_lifecycle_configuration
现在我能做的就是
lifecycle {
ignore_changes = [lifecycle_rule]
}
忽略事后应用的更改。我经常使用这种技术,例如,如果 AMI 映像更新,我不希望重新创建我的 EC2 实例。
但是,如果我只打算执行规则的较小子集(例如,仅设置每个前缀的到期时间),我可以使用dynamic
块。
例如
variable "cache_expiration_rules" {
description = "Expiration rules for S3 cache"
default = []
type = list(object({ prefix = string, days = number }))
}
resource "aws_s3_bucket" "cache" {
bucket = local.cache_bucket_name
acl = "private"
force_destroy = false
lifecycle_rule {
id = "Common lifecycle rule"
abort_incomplete_multipart_upload_days = 1
enabled = true
transition {
days = 1
storage_class = "INTELLIGENT_TIERING"
}
}
dynamic "lifecycle_rule" {
for_each = var.cache_expiration_rules
content {
id = "${lifecycle_rule.value["prefix"]} expiration in ${lifecycle_rule.value["days"]} days"
enabled = true
prefix = lifecycle_rule.value["prefix"]
expiration {
days = lifecycle_rule.value["days"]
}
}
}
}