0

我有一个通过terraform aws lambda module创建的 Lambda 。它指向一个版本化的 Lambda,因为我使用了保留并发。它也驻留在 VPC 中。

配置如下所示:

module "my-lambda" {
  source  = "terraform-aws-modules/lambda/aws"
  version = "~> v1.45.0"

  function_name         = "${local.lambda_name}"
  description           = local.lambda_name
  handler               = "handler.handler"
  runtime               = "python3.8"
  hash_extra            = local.lambda_name
  attach_tracing_policy = true
  tracing_mode          = "Active"
  publish               = true
  vpc_security_group_ids = [
// required VPC security groups
  ]
  vpc_subnet_ids = var.private_subnet_ids
  source_path = [
    // ... abriged
  ]

  build_in_docker                           = true
  provisioned_concurrent_executions         = var.provisioned_concurrency_lambdas
  create_current_version_allowed_triggers   = true
  create_unqualified_alias_allowed_triggers = false

  allowed_triggers = {
    APIGateway = {
      service    = "apigateway"
      source_arn = "${module.my_api_gateway.this_apigatewayv2_api_execution_arn}/*"
    }
  }

  attach_policies = true
  policies = [
    // policies needed for a VPC lambda
  ]
}

我发现在 terraform 计划中,即使我不做任何更改并反复发出问题terraform plan,也会发生这种替换 - 这会导致重新创建 API Gateway 权限并且基本上会导致短暂的停机:

  # module.my_entire_api.module.my-lambda.aws_lambda_permission.current_version_triggers["APIGateway"] must be replaced
-/+ resource "aws_lambda_permission" "current_version_triggers" {
      ~ id            = "APIGateway" -> (known after apply)
      ~ qualifier     = "1" -> (known after apply) # forces replacement
        # (5 unchanged attributes hidden)
    }

  #  module.my_entire_api.module.my-lambda.aws_lambda_provisioned_concurrency_config.current_version[0] must be replaced
-/+ resource "aws_lambda_provisioned_concurrency_config" "current_version" {
      ~ id                                = "env-my-lambda:1" -> (known after apply)
      ~ qualifier                         = "1" -> (known after apply) # forces replacement
        # (2 unchanged attributes hidden)
    }

还有一些其他 Lambda 不在 VPC 中运行。目前我没有看到这些效果,虽然我不完全确定它永远不会发生。

可以肯定的是,我不关心并发配置,因为重新创建它不会导致停机。但我想配置模块,以便不会重新创建 aws_lambda_permission。我怎么可能做到这一点?

4

2 回答 2

1

terraform-provider-aws 3.13.0 及更高版本(包括 3.25.0)中的一个问题导致 VPCterraform-provider-aws的 lambda 在每次应用时都会更新 #17385


来自文档如何部署和管理 Lambda 函数?

publish               = true

通常,Lambda 函数资源会在源代码更改时更新。如果publish = true指定,还将创建一个新的 Lambda 函数版本。

发布标志

variable "publish" {
  description = "Whether to publish creation/change as new Lambda Function Version."
  type        = bool
  default     = false
}

aws_lambda_permission

resource "aws_lambda_permission" "current_version_triggers" {
  for_each = var.create && var.create_function && !var.create_layer && var.create_current_version_allowed_triggers ? var.allowed_triggers : {}

  function_name = aws_lambda_function.this[0].function_name
  qualifier     = aws_lambda_function.this[0].version

因此,每次部署新版本时,都会部署相应资源中引用的新版本以更新策略。因此,它每次都会触发更新。

在 AWS Lambda 函数中,部署和发布有什么区别?

根据您为部署和发布派生上下文的位置,通常部署意味着使用新代码重新部署您的 lambda,而发布是增加您的 lambda 版本(而不是重新部署代码)。

于 2021-04-12T14:12:43.647 回答
0

我面临的问题归结为几件事。

  • 当您执行预置并发时,您必须“发布”您的 lambda,以便它们具有适当的版本限定符(例如“1”和 NOT $LATEST),因此允许网关调用 Lambda 的 Lambda 权限与特定的 Lambda 版本相关联。当您制作另一个版本时,这些权限将被销毁并为新的 Lambda 版本重新创建。create_before_destroy生命周期标志可能会有所帮助。当没有更改时,我还没有看到为非 VPC lambda 重新创建这些;更改 Lambda 后,在删除和重新创建 Lambda 中为 API Gateway 保留的并发和权限之间有几分钟的时间。
  • 此外,即使 Lambda 没有更改,VPC Lambdas 也可以体验并发和权限的重建,Terraform 错误https://github.com/hashicorp/terraform-provider-aws/issues/17385

解决方案似乎根本不处理 Lambda 的权限,而是提供 API 网关“凭据”(即具有 Lambda InvokeFunction 权限的角色),允许它调用 Lambda。这样,当调用 AWS 网关“集成”(= Lambda)时,它会承担角色。在这种情况下,不需要 Lambda 端的权限。我的测试表明,在这种情况下,更新 Lambda 的顺序是正确的:无需为 VPC lambda 重新创建资源,并且在更新 Lambda 时,首先部署一个新版本,然后 API Gateway 转移到它(因此,没有停机时间发生)。在一定负载下的生产测试也证实了我们在实践中没有看到中断。

这是允许 Lambda 调用的 API Gateway 配置的片段。它遵循https://medium.com/@jun711.g/aws-api-gateway-invoke-lambda-function-permission-6c6834f14b61上的配方。


resource "aws_iam_role" "api_gateway_credentials_call_lambda" {
  assume_role_policy = jsonencode({
    Version = "2012-10-17",
    Statement = [
      {
        Effect = "Allow",
        Principal = {
          Service = "lambda.amazonaws.com"
        },
        Action = "sts:AssumeRole"
      },
      {
        Effect = "Allow",
        Principal = {
          Service = "apigateway.amazonaws.com"
        },
        Action = "sts:AssumeRole"
      }
    ]
  })
  inline_policy {
    name = "permission-apigw-lambda-invokefunction"
    policy = jsonencode({
      "Version" : "2012-10-17",
      "Statement" : [
        {
          Effect   = "Allow",
          Action   = "lambda:InvokeFunction",
          Resource = "arn:aws:lambda:*:${data.aws_caller_identity.current.account_id}:function:*"
        }
      ]
    })
  }
}

请注意,最后一条Resource = 指令将允许此角色调用所有 Lambda。您可能希望将这些权利限制为 lambda 的子集,以提高安全性并减少人为错误。

设置此角色后,我使用serverless.tf 框架中的流行模块 apigateway-v2配置 API 网关:

module "api_gateway" {
  source  = "terraform-aws-modules/apigateway-v2/aws"
  version = "~> 0.14.0"

  # various parameters ...

  # Routes and integrations
  integrations = {

    "GET /myLambda" = {
      integration_type        = "AWS_PROXY"
      integration_http_method = "POST"
      payload_format_version  = "2.0"
      lambda_arn              = my_lambda_qualified_arn
      # This line enables the permissions:
      credentials_arn         = aws_iam_role.api_gateway_credentials_call_lambda.arn
    }

于 2021-04-27T13:18:59.767 回答