在 Terraform 工作空间之间共享资源

Posted

技术标签:

【中文标题】在 Terraform 工作空间之间共享资源【英文标题】:Sharing resources between Terraform workspaces 【发布时间】:2019-03-07 10:37:44 【问题描述】:

我正在使用 AWS 中的 Terraform 部署一个基础设施。此基础架构可以部署到不同的环境中,我正在使用工作区。

部署中的大多数组件应该为每个工作区单独创建,但我希望在它们之间共享几个关键组件,主要是:

IAM 角色和权限 他们应该使用相同的 API 网关,但每个工作区应该部署到不同的路径和方法

例如:

resource "aws_iam_role" "lambda_iam_role" 
  name = "LambdaGeneralRole"
  policy = <...>


resource "aws_lambda_function" "my_lambda" 
  function_name = "lambda-$terraform.workspace"
  role = "$aws_iam_role.lambda_iam_role.arn"

第一个资源是一个 IAM 角色,应该在该 Lambda 的所有实例之间共享,并且不应多次重新创建。

第二个资源是一个 Lambda 函数,其名称取决于当前工作区,因此每个工作区将部署并跟踪不同 Lambda 的状态。

如何在不同的 Terraform 工作空间之间共享资源及其状态?

【问题讨论】:

【参考方案1】:

对于共享资源,我在单独的模板中创建它们,然后在需要有关它们的信息的模板中使用terraform_remote_state 引用它们。

以下是我如何实现它,可能还有其他方法可以实现它。 YMMV

在共享服务模板(您将放置 IAM 角色的位置)中,我使用 Terraform 后端将共享服务模板的输出数据存储在 Consul 中。您还需要output 任何您想在其他模板中使用的信息。

shared_services 模板

terraform 
  backend "consul" 
    address = "consul.aa.example.com:8500"
    path    = "terraform/shared_services"
  


resource "aws_iam_role" "lambda_iam_role" 
  name = "LambdaGeneralRole"
  policy = <...>


output "lambda_iam_role_arn" 
  value = "$aws_iam_role.lambda_iam_role.arn"

Terraform 中的“后端”决定了如何加载状态以及如何执行应用等操作。这种抽象支持非本地文件状态存储、远程执行等。

在单个模板中,您使用terraform_remote_state 将后端作为数据源调用,并且可以使用该模板中的数据。

terraform_remote_state:

从远程后端检索状态元数据

单独的模板

data "terraform_remote_state" "shared_services" 
    backend = "consul"
    config 
        address = "consul.aa.example.com:8500"
        path    = "terraform/shared_services"
    


# This is where you use the terraform_remote_state data source
resource "aws_lambda_function" "my_lambda" 
  function_name = "lambda-$terraform.workspace"
  role = "$data.terraform_remote_state.shared_services.lambda_iam_role_arn"

参考文献

https://www.terraform.io/docs/state/remote.html

https://www.terraform.io/docs/backends/

https://www.terraform.io/docs/providers/terraform/d/remote_state.html

【讨论】:

我没有测试过它,但我认为没有理由不应该这样做,只要terraform.tfstate 文件可用。 我刚刚尝试过,我可以确认terraform_remote_state 可以与backend = "local" 一起使用,甚至没有指定任何后端,这似乎将local 作为默认值。 就我而言,我需要检索仅存在于我的生产工作区中的资源。我在文档中发现您可以在terraform_remote_state 中指定workspace = "production"。这很方便。 我不太明白的部分是output的使用方式。我可以从存在该资源的工作空间中输出该资源,以便从不存在该资源的工作空间中引用它。但是,输出在不存在该资源的工作区中不起作用。我错过了什么? 我认为这实际上并不能回答涉及工作空间时的问题。它只是描述了如何从单独的状态中检索。 lambda_iam_role 仍然在每个工作区中创建,这是问题(和我自己)试图避免的。【参考方案2】:

如果name 值与已配置的资源匹配,则具有name 属性的aws_iam_role 等资源将不会创建新实例。

因此,以下将创建一个名为 LambdaGeneralRoleaws_iam_role

resource "aws_iam_role" "lambda_iam_role" 
  name = "LambdaGeneralRole"
  policy = <...>


...

resource "aws_iam_role" "lambda_iam_role_reuse_existing_if_name_is_LambdaGeneralRole" 
  name = "LambdaGeneralRole"
  policy = <...>

类似地,aws 提供程序将有效地创建一个 S3 bucket 名称 my-store 给定以下条件:

resource "aws_s3_bucket" "store-1" 
  bucket        = "my-store"
  acl           = "public-read"
  force_destroy = true


...

resource "aws_s3_bucket" "store-2" 
  bucket        = "my-store"
  acl           = "public-read"
  force_destroy = true

即使资源被定义为具有各自独立 Terraform 状态的不同工作区,此行为仍然有效。


要充分利用这种方法,请将共享资源定义为单独的配置。这样,您就不会冒着在运行 terraform destroy 后破坏共享资源的风险。

【讨论】:

这不会有一些副作用,比如调用“terraform destroy”会破坏多个工作空间使用的共享基础架构吗? 如果您的所有资源都在一个配置中定义,那就可以了。

以上是关于在 Terraform 工作空间之间共享资源的主要内容,如果未能解决你的问题,请参考以下文章

工作空间之间的 Android ccache 共享

模块中的 Terraform 提供程序/变量共享

Terraform gcp 与共享 vpc、gke

Terraform适用于现有的ARM资源。需要国家吗?

使用 Terraform 模块创建资源,其中一些资源由模块共享

在 OS X 上的 OpenGL 上下文之间共享数据(不同的版本/配置文件)