在其他 terraform 文件中使用输出 terraform 文件

Posted

技术标签:

【中文标题】在其他 terraform 文件中使用输出 terraform 文件【英文标题】:Using outputs terraform files in other terraform files 【发布时间】:2021-12-18 10:27:19 【问题描述】:

我是 terraform 的新手,有几个问题。在 terraform 中有没有办法在另一个 tf 文件中使用模块的输出,没有有一个“主”terraform 文件,或者在同一个文件中定义两个模块?

例如,这是一个项目结构:

project/
├── networking
│   ├── init.tf
│   ├── terraform.tfvars
│   ├── variables.tf
│   └── vpc.tf
├── prd-project-1
│   ├── init.tf
│   ├── instances.tf
│   ├── terraform.tfvars
│   └── variables.tf
├── prd-project-2
│   ├── init.tf
│   ├── instances.tf
│   ├── terraform.tfvars
│   └── variables.tf
├── prd-project-3
│   ├── init.tf
│   ├── instances.tf
│   ├── terraform.tfvars
│   └── variables.tf
├── test
│   ├── init.tf
│   ├── instances.tf
│   ├── terraform.tfvars
│   └── variables.tf

vpc.tf 将创建一个 VPC 和子网。 instances.tf 将根据之前在 vpc.tf 中创建的 vpc-id 和子网创建 EC2 实例。我想将这些作为两个单独的操作来处理/管理。 IE。首先,我会运行 terraform 来创建 vpc 和子网,然后我可能会运行 terraform 来在 prod/test 中为各种项目创建实例。在此示例中,我将只有 1 个 VPC 用于测试,1 个 VPC 用于生产。我不希望每个项目都有一个 VPC(我再次假设如果在其中一个子项目中引用了 vpc.tf 模块,TF 可能会创建它)。

以这种方式管理 terraform 代码是最佳做法吗?我担心的是,如果最终有很多项目需要 EC2 实例,我不希望所有这些都集中在一个巨大的 main.tf 中。我认为,只要可以引用 vpc 输出,单独维护这些都更安全/更清洁。如果我正在建立一个新项目,我也不希望我的 terraform 计划/应用程序缓慢并检查每个项目的每个资源。

我的问题的第二部分是 - 考虑以下代码 sn-p:

module "main-vpc" 
  source     = "../modules/vpc"
  ENV        = "prod"
  AWS_REGION = var.AWS_REGION


module "instances" 
  source         = "../modules/instances"
  ENV            = "prod"
  VPC_ID         = module.main-vpc.vpc_id
  PUBLIC_SUBNETS = module.main-vpc.public_subnets
 

terraform 是否足够聪明,可以确定已经使用 ENV = prod 创建了 VPC,并且如果我在另一个 tf 文件/项目中调用相同的“main-vpc”模块,它不会尝试重新创建它?

我在 *** 上阅读了其他一些帖子,但它们都暗示一个模块的输出只能在同一个 tf 文件中的另一个模块中引用。

我看过的其他一些帖子:

Using outputs from other tf files in terraform Pass terraform output from one file to another Terraform module - output variable as input for another module Terraform structure for two aws accounts

【问题讨论】:

抱歉,不清楚你想做什么。拥有 main.tf 有什么问题? 例如,如果我有 100 个项目。我想对项目 84 进行更改,运行 terraform plan/apply 将是一项长期/耗时的任务,因为它需要遍历每个项目并检查更改。相反,我想包含和部署单独的项目,但参考其他模块的输出,例如VPC ID 和子网 ID。 我认为你必须重新设计你的方法。您要么将项目完全分离,要么使用 terraform 工作区将它们分开。 【参考方案1】:

如果您想保留当前的文件夹结构,最好在每个项目中添加main.tf

project/
├── networking
│   ├── init.tf
│   ├── terraform.tfvars
│   ├── variables.tf
│   └── vpc.tf
├── prd-project-1
│   ├── main.tf
│   ├── init.tf
│   ├── instances.tf
│   ├── terraform.tfvars
│   └── variables.tf
├── prd-project-2
│   ├── main.tf
│   ├── init.tf
│   ├── instances.tf
│   ├── terraform.tfvars
│   └── variables.tf
├── prd-project-3
│   ├── main.tf
│   ├── init.tf
│   ├── instances.tf
│   ├── terraform.tfvars
│   └── variables.tf
├── test
│   ├── init.tf
│   ├── instances.tf
│   ├── terraform.tfvars
│   └── variables.tf

那么每个main.tf 将如下所示:

module "main-vpc" 
  source     = "../networking"
  ENV        = "prod"
  AWS_REGION = var.AWS_REGION


module "instances" 
  source         = "../instances"
  ENV            = "prod"
  VPC_ID         = module.main-vpc.vpc_id
  PUBLIC_SUBNETS = module.main-vpc.public_subnets

这样您就可以将项目分开,并且每个项目都有自己的 TF 状态文件

terraform 是否足够智能,可以确定 VPC 是否已使用 ENV 创建

不,不是。您必须为此编写自己的逻辑。一种常见的方式是通过一个变量

variable "vpc_id" 
  default = ""

如果您没有为给定项目明确指定vpc_id,它将创建新的 VPC。否则,它将使用您作为输入参数提供的var.vpc_id。使用data sources,您将获得该 VPC 的其他信息,例如其子网。

进行此设置后,您将首先 cd 到每个项目文件夹,然后再部署它,例如

cd ./prd-project-1
terraform apply

【讨论】:

【参考方案2】:

如果我理解您的问题,您希望拥有仍然可以访问彼此输出的独立项目。因此,例如,启动 EC2 实例的项目可以引用在创建 VPC 的项目中定义的子网。

有两种方法可以做到这一点。首先,您可以使用数据源查询当前的部署环境。例如,以下内容将查找带有 ENV 标签且值为“prod”的 VPC(假设我没有输入任何拼写错误):

data "aws_vpc" "prod" 
  tags =  "ENV": "prod" 

其次,您可以使用远程状态(为了安全起见,这无论如何都是个好主意)。每个项目都会将其输出写入数据存储(S3 很常见,但 Terraform 提供自己的存储),并且它们会被其他项目引用。

虽然 SO 不喜欢链接,但我无法比 Terraform 文档更好地解释它:https://www.terraform.io/docs/language/state/backends.html

【讨论】:

@Marcin - 我想你想回复 OP? 非常感谢。这很有意义,并且完美地回答了我的问题。

以上是关于在其他 terraform 文件中使用输出 terraform 文件的主要内容,如果未能解决你的问题,请参考以下文章

可以在控制台输出中使用Terraform屏蔽变量吗?

防止 terraform 函数“模板文件”输出 heredoc

在 azure 后端存储中使用状态文件将 terraform 的输出传递到 Azure Devops Pipeline

Terraform 模块输出用作其他模块中的输入,特别是 for_each

为啥 terraform 试图重建已经提供的基础设施?

在模块内的模块之间传递 Terraform 变量?