与 AWS 上的无服务器框架一样,使用 Terraform 创建隔离堆栈

create isolated stacks with terraform as with the serverless framework on AWS

我正在 AWS 上开发无服务器数据管道。相比 Serverless framework, Terraform 对 Glue 等服务有更好的支持。

Serverless 的好处是您可以在部署时定义 --stage 参数。这允许在 AWS 上创建一个独立的堆栈。在我们的数据管道上开发新功能时,我可以像

这样部署我的代码状态
serverless deploy --stage my-new-feature

这让我可以在我与同事共享的 AWS 账户上进行独立的集成测试。这可能使用 Terraform 吗?

你看过工作区了吗? https://www.terraform.io/docs/state/workspaces.html

Terraform 通过状态管理资源。

如果资源已存在于状态文件中,并且 Terraform 未检测到配置、状态和提供程序中的任何差异之间的任何漂移(例如,某些内容在 AWS 控制台或其他工具中发生了更改),则它将显示没有变化。如果它确实检测到某种形式的漂移,那么 plan 将向您显示它需要进行哪些更改才能将提供程序中的现有状态推向 Terraform 代码中定义的状态。

不同环境之间的分离状态

如果您希望拥有多个环境甚至其他资源,这些资源彼此独立且不由同一 Terraform 操作管理(例如 planapplydestroy) 然后你想把它们分成不同的状态文件。

实现此目的的一种方法是按环境分隔 Terraform 代码,并使用与代码库目录结构相匹配的状态文件。一个简单的示例可能如下所示:

terraform/
├── production
│   ├── main.tf -> ../stacks/main.tf
│   └── terraform.tfvars
├── stacks
│   └── main.tf
└── staging
    ├── main.tf -> ../stacks/main.tf
    └── terraform.tfvars

stacks/main.tf

variable "environment" {}

resource "aws_lambda_function" "foo" {
  function_name = "foo-${var.environment}"
  # ...
}

production/terraform.tfvars

environment = "production"

staging/terraform.tfvars

environment = "staging"

这使用了符号链接,因此暂存和生产与代码保持一致,只有 terraform.tfvars 文件引入了更改。在本例中,它更改了 Lambda 函数的名称以包含环境。

这是我通常推荐的静态环境,因为通过查看存在哪些环境的 code/directory 结构会更清楚。

动态环境

但是,如果您有更多的动态环境,例如每个功能分支,那么直接在 terraform.tfvars 文件中硬编码环境名称是行不通的。

在这种情况下,我会推荐这样的东西:

terraform/
├── production
│   ├── main.tf -> ../stacks/main.tf
│   └── terraform.tfvars
├── review
│   ├── main.tf -> ../stacks/main.tf
│   └── terraform.tfvars
├── stacks
│   └── main.tf
└── staging
    ├── main.tf -> ../stacks/main.tf
    └── terraform.tfvars

这以相同的方式工作,但我会从 review 结构中省略 environment 变量,以便以交互方式或通过 CI 环境变量(例如 export TF_VAR_environment=${TRAVIS_BRANCH}当 运行 在 Travis CI 中时,调整它以支持您使用的任何 CI 系统)。

在不同分支的审阅环境之间保持状态分离

虽然这只会让你成功一半,因为当另一个人试图将它与另一个分支一起使用时,他们会看到 Terraform 想要 destroy/update 已经由 运行 Terraform 创建的任何资源,如果你只是使用默认 workspace.

工作区提供了一个以更动态的方式分离状态的选项,还允许您 interpolate the workspace name into Terraform code:

resource "aws_instance" "example" {
  tags {
    Name = "web - ${terraform.workspace}"
  }

  # ... other arguments
}

相反,审阅环境将需要创建或使用仅适用于该分支的动态工作区。您可以通过 运行 以下 command:

terraform workspace new [NAME]

如果工作区已经存在,那么您应该改用以下 command:

terraform workspace select [NAME]

在 CI 中,您可以使用与以前相同的环境变量来自动使用分支名称作为您的工作区名称。