如何使用 Terraform 向现有 AWS S3 存储桶添加生命周期规则

如何使用 Terraform 向现有 AWS S3 存储桶添加生命周期规则

我有一个现有的 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"]
      }
    }
  }

}

相关内容