在Terraform工作区之间共享资源

29

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

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

  • 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 工作区之间共享资源及其状态?

2个回答

30

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

接下来是我如何实现这一点,可能还有其他的实现方式。您的情况可能会有所不同。

在共享服务模板中(您将在其中放置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中,“backend”决定了如何加载状态(state),以及如何执行apply等操作。这种抽象使得非本地文件状态存储、远程执行等成为可能。在单独的模板中,您可以使用terraform_remote_state作为数据源调用后端,并可以在该模板中使用该数据。terraform_remote_state:从远程后端检索状态元数据。 “individual template”
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文件可用,就没有理由不行。 - kenlukas
我刚刚尝试了一下,可以确认 terraform_remote_state 可以与 backend = "local" 一起使用,甚至不指定任何后端也可以,似乎会将 local 作为默认值。 - Bastian
2
在我的情况下,我需要检索仅存在于我的生产工作区中的资源。我在文档中发现,您可以在terraform_remote_state中指定workspace =“production”。这很方便。 - Bastian
1
我不确定理解的部分是如何使用“output”。我可以从资源所在的工作区输出该资源,以便从资源不存在的工作区引用它。但是,然后在资源不存在的工作区中,输出无法正常工作。我错过了什么? - Bastian
1
我认为当涉及工作区时,这并没有真正回答问题。它只是描述了如何从单独的状态中检索。lambda_iam_role仍然在每个工作区中创建,这正是问题(和我自己)试图避免的。 - Andy Shinn
如果在共享模板中销毁了资源(该模板拥有不同的状态文件),那么当应用引用该已销毁资源的单个资源时,这是否会导致应用失败?拆分状态文件会导致 terraform 不知道该销毁哪些单个资源。 - Mario Ishac

-1

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

因此,以下内容将创建一个名为LambdaGeneralRole的单个aws_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提供程序将有效地创建一个名为my-storeS3 bucket
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”会破坏多个工作区使用的共享基础设施? - Oren
1
如果您的所有资源都在单个配置中定义,那么它就会生效。 - Igwe Kalu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接