Terraform - 每次申请时将文件上传到 S3

Terraform - Upload file to S3 on every apply

我需要上传一个文件夹到 S3 Bucket。但是当我第一次申请的时候。它只是上传。但是我这里有两个问题:

  1. 上传的版本输出为空。我希望有一些 version_id 像 1, 2, 3
  2. 再次运行宁terraform apply时,显示Apply complete! Resources: 0 added, 0 changed, 0 destroyed。我希望在我 运行 terraform apply 并创建新版本时一直上传。

我做错了什么?这是我的 Terraform 配置:

resource "aws_s3_bucket" "my_bucket" {
  bucket = "my_bucket_name"

  versioning {
    enabled = true
  }
}

resource "aws_s3_bucket_object" "file_upload" {
  bucket = "my_bucket"
  key    = "my_bucket_key"
  source = "my_files.zip"
}

output "my_bucket_file_version" {
  value = "${aws_s3_bucket_object.file_upload.version_id}"
}

您不应该使用 Terraform 来执行此操作。 Terraform 应该编排和配置您的基础架构及其配置,而不是文件。也就是说,terraform 不知道您的文件发生了变化。除非您更改它们的名称,否则 terraform 不会更新状态。

此外,最好使用 local-exec 来做到这一点。类似于:

resource "aws_s3_bucket" "my-bucket" {
# ...

  provisioner "local-exec" {
     command = "aws s3 cp path_to_my_file ${aws_s3_bucket.my-bucket.id}"
  }
}

Terraform 仅在检测到配置和远程对象属性之间存在差异时才对远程对象进行更改。在您目前编写的配置中,配置仅包含文件名。它不包含任何关于文件内容的内容,因此 Terraform 无法对文件更改做出反应。

要进行后续更改,有几个选项:

  • 您可以为每个新版本使用不同的本地文件名。
  • 您可以为每个新版本使用不同的远程对象路径。
  • 无论本地文件名或对象路径如何,您都可以使用对象 etag 让 Terraform 识别内容何时更改。

在这种情况下,最后一个似乎最接近您想要的。为此,添加 etag 参数并将其设置为文件的 MD5 哈希:

resource "aws_s3_bucket_object" "file_upload" {
  bucket = "my_bucket"
  key    = "my_bucket_key"
  source = "${path.module}/my_files.zip"
  etag   = "${filemd5("${path.module}/my_files.zip")}"
}

有了这个额外的参数,Terraform 将检测磁盘上文件的 MD5 散列值何时与远程存储在 S3 中的不同,并计划相应地更新对象。


(我不确定 version_id 发生了什么。只要在存储桶上启用了版本控制,它就应该可以工作。)

现在首选的解决方案是使用source_hash属性。请注意,aws_s3_bucket_object 已替换为 aws_s3_object

locals {
  object_source = "${path.module}/my_files.zip"
}

resource "aws_s3_object" "file_upload" {
  bucket      = "my_bucket"
  key         = "my_bucket_key"
  source      = local.object_source
  source_hash = filemd5(local.object_source)
}