【问题标题】:Sharing resources between Terraform workspaces在 Terraform 工作空间之间共享资源
【发布时间】: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 工作空间之间共享资源及其状态?

【问题讨论】:

    标签: amazon-web-services terraform devops terraform-provider-aws


    【解决方案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”会破坏多个工作空间使用的共享基础架构吗?
    • 如果您的所有资源都在一个配置中定义,那就可以了。
    猜你喜欢
    • 2021-09-24
    • 2020-04-26
    • 1970-01-01
    • 1970-01-01
    • 2021-10-10
    • 2013-12-10
    • 2011-05-11
    • 2019-10-07
    相关资源
    最近更新 更多