首页 > 解决方案 > 用于 Localstack 的 Terraform 覆盖提供程序

问题描述

我有一个正在部署到 AWS 中的带有 Terraform 代码的 Git 存储库。我将 Localstack 添加到此存储库,以便我可以在计划之前进行更高级别的验证测试并应用到我的真实 AWS 账户。为了使用 Localstack,我必须使用自定义端点创建一个新的提供程序:

provider "aws" {
  alias  = "real"
  region = "${local.aws_region}"
}

provider "aws" {
  alias                       = "fake"
  region                      = "${local.aws_region}"
  access_key                  = "fake"
  secret_key                  = "fake"
  skip_credentials_validation = true
  skip_metadata_api_check     = true
  skip_requesting_account_id  = true

  endpoints {
    dynamodb = "http://localhost:4566"
    lambda   = "http://localhost:4566"
    kinesis  = "http://localhost:4566"
  }
}

如何在不复制代码的情况下将一个提供商用于 Localstack,将一个提供商用于 AWS?

标签: terraformlocalstack

解决方案


不幸的是,由于这两种情况下的配置结构有很大的不同,因此如果不使结果配置看起来很复杂,实际上不可能使其动态切换,但可以使用 Terraform 语言表达式运算符和dynamic块来有条件地设置所有提供程序参数,因此具有具有动态设置的单个提供程序配置,而不是两个单独的提供程序配置。

首先要决定的是你将如何在两种可能性之间做出决定。由于您的 localstack 伪基础设施将不可避免地与“真实”基础设施不同,我希望您希望为它使用单独的状态,因此这可能是使用单独的工作区进行开发/测试的合理情况,我'将编写此示例,假设只要选择了工作空间,localstack 配置就应该处于活动状态dev。如果那不是您想要的,那么希望这仍然足以适应您的需求。

locals {
  use_localstack = (terraform.workspace == "dev")

  aws_settings = (
    local.use_localstack ?
    {
      region     = local.aws_region
      access_key = "fake"
      secret_key = "fake"

      skip_credentials_validation = true
      skip_metadata_api_check     = true
      skip_requesting_account_id  = true

      override_endpoint = "http://localhost:4566"
    } :
    {
      region     = local.aws_region
      access_key = null
      secret_key = null
      
      skip_credentials_validation = null
      skip_metadata_api_check     = null
      skip_requesting_account_id  = null

      override_endpoint = null
    }
  )
}

provider "aws" {
  region     = local.aws_settings.region
  access_key = local.aws_settings.access_key
  secret_key = local.aws_settings.secret_key

  skip_credentials_validation = local.aws_settings.skip_credentials_validation
  skip_metadata_api_check     = local.aws_settings.skip_metadata_api_check
  skip_requesting_account_id  = local.aws_settings.skip_requesting_account_id

  dynamic "endpoints" {
    for_each = local.aws_settings.override_endpoint[*]
    content {
      dynamodb = endpoints.value
      lambda   = endpoints.value
      kinesis  = endpoints.value
    }
  }
}

以上依赖于 Terraform 语言的两个特定行为:

  • 设置将传递给提供者的参数时,设置null始终与忽略该参数相同,因为 Terraform 在内部通过隐式设置未设置的参数来处理未设置的参数null
  • 与非列表值一起使用[*]会自动将其转换为零元素列表或一元素列表,具体取决于该值是否为null. 这允许我们仅在属性为非空时动态声明endpoints块,然后将其值写入所有三个被覆盖的端点参数。override_endpoint

推荐阅读