Terraform替换存储桶对象而不是版本控制

时间:2019-07-30 19:32:23

标签: amazon-web-services terraform

我正在设置一些Terraform来管理lambda和s3存储桶,并对s3的内容进行版本控制。创建基础结构的第一个版本很好。发布第二个版本时,terraform会替换该zip文件,而不是创建一个新版本。

我曾尝试在terraform配置中向s3存储桶添加版本控制,并将api版本移至可变字符串。

data "archive_file" "lambda_zip" {
  type        = "zip"
  source_file = "main.js"
  output_path = "main.zip"
}

resource "aws_s3_bucket" "lambda_bucket" {
  bucket = "s3-bucket-for-tft-project"
  versioning {
    enabled = true
  }
}
resource "aws_s3_bucket_object" "lambda_zip_file" {
  bucket = "${aws_s3_bucket.lambda_bucket.bucket}"
  key    = "v${var.api-version}-${data.archive_file.lambda_zip.output_path}"
  source = "${data.archive_file.lambda_zip.output_path}"
}

resource "aws_lambda_function" "lambda_function" {
  s3_bucket         = "${aws_s3_bucket.lambda_bucket.bucket}"
  s3_key            = "${aws_s3_bucket_object.lambda_zip_file.key}"
  function_name     = "lambda_test_with_s3_version"
  role              = "${aws_iam_role.lambda_exec.arn}"
  handler           = "main.handler"
  runtime           = "nodejs8.10"
}

我希望输出是另一个zip文件,但是lambda现在指向新版本,并且如果var.api-version被更改,则能够返回到旧版本。

1 个答案:

答案 0 :(得分:0)

Terraform并不是用于创建这种“工件”对象的,在该对象中,每个新版本都应与其之前的版本分开。

data.archive_file数据源是在AWS Lambda的早期添加到Terraform的,当时唯一的将Terraform值传递给Lambda函数的方法是检索所需的zip工件,将其修改为包括以下内容的其他文件:这些设置,然后将 that 写入Lambda。

现在,AWS Lambda支持环境变量,因此不再建议使用该模式。相反,应该通过Terraform之外的一些单独的构建过程来创建部署工件,并将其记录在Terraform可以发现它们的某个位置。例如,您可以使用SSM参数存储来记录当前所需的版本,然后让Terraform读取该版本以确定要检索的工件:

data "aws_ssm_parameter" "lambda_artifact" {
  name = "lambda_artifact"
}

locals {
  # Let's assume that this SSM parameter contains a JSON
  # string describing which artifact to use, like this
  # {
  #   "bucket": "s3-bucket-for-tft-project",
  #   "key": "v2.0.0/example.zip"
  # }
  lambda_artifact = jsondecode(data.aws_ssm_parameter.lambda_artifact)
}

resource "aws_lambda_function" "lambda_function" {
  s3_bucket         = local.lambda_artifact.bucket
  s3_key            = local.lambda_artifact.key
  function_name     = "lambda_test_with_s3_version"
  role              = aws_iam_role.lambda_exec.arn
  handler           = "main.handler"
  runtime           = "nodejs8.10"
}

此构建/部署分离允许执行三种不同的操作,而在Terraform中完成所有操作仅允许执行一项操作:

  • 要发布新版本,您可以运行构建过程(也许在CI系统中),然后将其生成的工件推送到S3并将其记录为SSM参数中的最新版本,然后触发Terraform运行部署它。
  • 要在不部署新功能版本的情况下更改基础结构的其他方面,只需运行Terraform而不更改SSM参数,Terraform将使Lambda功能保持不变。
  • 如果发现新版本有缺陷,则可以将较旧工件的位置写入SSM参数中,然后运行Terraform部署该先前版本。

Terraform指南Serverless Applications with AWS Lambda and API Gateway中对此方法有更完整的描述,该指南以Lambda Web应用程序为例,但也可以应用于许多其他AWS Lambda用例。使用SSM只是一个例子。 Terraform可以使用data source检索的任何数据都可以用作中介,以使构建和部署步骤彼此分离。

此一般想法可应用于各种代码构建工件以及Lambda zip文件。例如:使用HashiCorp Packer创建的自定义AMI,使用docker build创建的Docker映像。将构建过程,版本选择机制和部署过程分开,可以提供一定程度的工作流灵活性,可以同时支持快乐路径在事件发生期间采取的任何特殊路径。