使用 terraform 根据一组变量创建多个资源

The*_*ton 0 terraform terraform-provider-azure

我有一组变量terraform.tfvars

resource_groups = {
    cow = { 
        name     = "Cow"
        location = "eastus" 
    },    
    horse = { 
        name     = "Horse"
        location = "eastus" 
    },    
    chicken = { 
        name     = "Chicken"
        location = "westus2" 
    },    
}
Run Code Online (Sandbox Code Playgroud)

我的main.tf样子是这样的:


...
module "myapp" {
 source = "./modules/myapp"
 resource_groups = var.resource_groups
}


variable "resource_groups" {}
...
Run Code Online (Sandbox Code Playgroud)

./modules/myapp.main.tf看起来像这样:

module "resource_group" {
  source = "../myapp.resource_group"
  resource_groups = var.resource_groups

  for_each = {
  for key, value in try(var.resource_groups, {}) : key => value
  if try(value.reuse, false) == false
  }
  
}

variable "resource_groups" {}

Run Code Online (Sandbox Code Playgroud)

看起来../myapp.resource_group像这样:

resource "azurerm_resource_group" "resource_group" {
name      = var.resource_groups.cow.name
location  = var.resource_groups.cow.location

}

variable "resource_groups" {}
Run Code Online (Sandbox Code Playgroud)

我希望看到之后terraform plan会添加三个新的 RG。事实上,我确实得到了三个新的迭代器,但它们都使用了牛 RG 的名称和位置,因为我指定了var.resource_groups.cow.name 问题是我尝试了各种不同的迭代器来代替 .cow。我无法让 terraform 使用文件中的其他变量terraform.tfvars。我尝试过方括号、星号和其他通配符。我被困住了。

我希望在一个地方定义一个资源,然后使用它根据变量映射创建该资源的多个实例。

指导将不胜感激。

谢谢。

账单

Mar*_*ins 5

对于这种情况,您需要决定您的模块是代表一个资源组还是代表多个资源组。对于仅包含一种资源的模块,该决定并不是特别重要,但我假设您将其分解为一个单独的模块,因为这不仅仅是单个资源组资源,因此您可以在以下两者之间做出决定:这两个基于此模块所代表的其他内容:您想要重复此模块中的所有内容,还是仅重复资源组资源?


如果您需要模块来表示单个资源组,那么您应该更改其输入变量以仅获取有关单个资源组的数据,然后在调用块中传递当前资源组的数据module

模块内部:

variable "resource_group" {
  type = object({
    name     = string
    location = string
  })
}

resource "azurerm_resource_group" "resource_group" {
  name      = var.resource_group.name
  location  = var.resource_group.location
}
Run Code Online (Sandbox Code Playgroud)

调用模块时:

variable "resource_groups" {
  type = map(
    object({
      name     = string
      location = string
    })
  )
}

module "resource_group" {
  source   = "../myapp.resource_group"
  for_each = var.resource_groups

  # each.value is the value of the current
  # element of var.resource_groups, and
  # so it's just a single resource group.
  resource_group = each.value
}
Run Code Online (Sandbox Code Playgroud)

使用此策略,您将使用以下地址声明资源实例,这表明重复发生在整个模块的级别,而不是其中的各个资源:

  • module.resource_group["cow"].azurerm_resource_group.resource_group
  • module.resource_group["horse"].azurerm_resource_group.resource_group
  • module.resource_group["chicken"].azurerm_resource_group.resource_group

如果您需要模块来表示完整的资源组集,那么该模块会将资源组的完整映射作为输入变量,而不是for_each在块上使用module。该for_each参数将属于嵌套资源。

模块内部:

variable "resource_groups" {
  type = map(
    object({
      name     = string
      location = string
    })
  )
}

resource "azurerm_resource_group" "resource_group" {
  for_each = var.resource_groups

  name      = each.value.name
  location  = each.value.location
}
Run Code Online (Sandbox Code Playgroud)

调用模块时:

variable "resource_groups" {
  type = map(
    object({
      name     = string
      location = string
    })
  )
}

module "resource_group" {
  source   = "../myapp.resource_group"

  # NOTE: No for_each here, because we need only
  # one instance of this module which will itself
  # then contain multiple instances of the resource.

  resource_group = var.resource_groups
}
Run Code Online (Sandbox Code Playgroud)

使用这一策略,您将使用以下地址声明资源实例,这表明该模块只有一个实例,但其中有多个资源实例:

  • module.resource_group.azurerm_resource_group.resource_group["cow"]
  • module.resource_group.azurerm_resource_group.resource_group["horse"]
  • module.resource_group.azurerm_resource_group.resource_group["chicken"]

从您共享的信息中不清楚哪种策略更适合您的情况,因为您描述的这个模块就好像它只是资源类型的一个薄包装azurerm_resource_group,因此并不清楚这个模块是什么代表,以及为什么它比resource "azurerm_resource_group"在根模块中编写内联块更有帮助。

在考虑上述哪种设计最适合您的用例时,我建议考虑Terraform 文档中何时编写模块中的建议。编写仅包含单个块的模块是可以的resource,但这通常适用于更复杂的资源类型,其中模块对一些本地约定进行硬编码,以便不需要在整个组织的 Terraform 配置中重新指定它们。

如果您只是将值直接传递给资源参数,没有额外的转换和额外的硬编码设置,那么这表明该模块没有用,并且resource内联编写块会更简单。