首页 > 解决方案 > Terraform 使用 for_each 引用另一个模块的输出

问题描述

我在引用另一个模块中的一个模块的输出时遇到问题。第一个模块中的资源是使用 for_each 部署的。第二个模块中的资源正在尝试引用来自第一个模块的资源

创建了2个模块

  1. 安全组
  2. 虚拟机

目的是将安全组分配给虚拟机

以下是安全组的模块


variable "configserver" {
  type = map(object({
    name              = string
    location          = string
    subnet            = string
    availability_zone = string
    vm_size           = string
    hdd_size          = string
  }))
}


module "configserver_nsg" {
  for_each = var.configserver

  source              = "../../../terraform/modules/azure-network-security-group"
  resource_group_name = var.resource_group_name
  tags                = var.tags
  location = each.value.location
  nsg_name = "${each.value.name}-nsg"

  security_rules = [
    {
      name              = "Office",
      priority          = "100"
      direction         = "Inbound"
      access            = "Allow"
      protocol          = "TCP"
      source_port_range = "*"
      destination_port_ranges = [
        "22"]
      source_address_prefix = "192.168.1.100"
      destination_address_prefixes = [
        module.configserver_vm[each.key].private_ip
      ]
    },
    

    {
      name                       = "Deny-All-Others"
      priority                   = 4096
      direction                  = "Inbound"
      access                     = "Deny"
      protocol                   = "*"
      source_port_range          = "*"
      destination_port_range     = "*"
      source_address_prefix      = "*"
      destination_address_prefix = "*"
    }

  ]
}

// Value


configserver = {
  config1 = {
    name              = "config1"
    location          = "eastus"
    subnet            = "services"
    availability_zone = 1
    vm_size           = "Standard_F2s_v2"
    hdd_size          = 30
  }
}

安全组模块源有一个输出文件,它输出 nsg 的 id

output "nsg_id" {
  description = "The ID of the newly created Network Security Group"
  value       = azurerm_network_security_group.nsg.id
}

一般来说,如果没有 for_each,我可以像这样访问 nsg_id

module.configserver_nsg.id

到目前为止这很好,现在的问题是我无法从另一个模块访问 nsg_id

module "configserver_vm" {
  for_each = var.configserver

  source         = "../../../terraform/modules/azure-linux-vm"
  resource_group = module.resource_group.name
  ssh_public_key = var.ssh_public_key
  tags           = var.tags
  vm_name            = each.value.name
  location           = each.value.location
  subnet_id          = each.value.subnet
  availability-zones = each.value.availability_zone
  vm_size            = each.value.vm_size
  hdd-size           = each.value.hdd_size
  nsg_id             = module.configserver_nsg[each.key].nsg_id
}

根据我对这些的研究,一些帖子(这里这里这里说我应该能够使用each.key遍历地图但是

nsg_id             = module.configserver_nsg[each.key].nsg_id

这会产生错误

Error: Cycle: module.configserver_nsg (close), module.configserver_vm.var.nsg_id (expand), module.configserver_vm.azurerm_network_interface_security_group_association.this, module.configserver_vm (close), module.configserver_nsg.var.security_rules (expand), module.configserver_nsg.azurerm_network_security_group.nsg, module.configserver_nsg.output.nsg_id (expand)

还有其他方法可以引用该值吗?

标签: terraformterraform-provider-azure

解决方案


正如我看到的第一个问题是您使用错误的方式从模块中引用configserver_nsgNSG id 的内容,它应该是这样的:

nsg_id             = module.configserver_nsg[each.value.name].nsg_id

@Matt 已经说过第二个问题。这是两个模块之间的循环依赖。造成循环依赖的东西是 NSG 规则,似乎 NSG 规则需要 VM 私有 IP 地址。据我所知,如果不进行更改,就无法解决循环依赖问题。因此,我建议您进行更改,将 NSG 规则与模块分开,并在两个模块之后configserver_nsg使用资源。azurerm_network_security_rule

最后,它看起来像这样:

variable "configserver" {
  type = map(object({
    name              = string
    location          = string
    subnet            = string
    availability_zone = string
    vm_size           = string
    hdd_size          = string
  }))
}


module "configserver_nsg" {
  for_each = var.configserver

  source              = "../../../terraform/modules/azure-network-security-group"
  resource_group_name = var.resource_group_name
  tags                = var.tags
  location = each.value.location
  nsg_name = "${each.value.name}-nsg"

  security_rules = [
    {
      
    },
    

    {
      name                       = "Deny-All-Others"
      priority                   = 4096
      direction                  = "Inbound"
      access                     = "Deny"
      protocol                   = "*"
      source_port_range          = "*"
      destination_port_range     = "*"
      source_address_prefix      = "*"
      destination_address_prefix = "*"
    }

  ]
}

// Value


configserver = {
  config1 = {
    name              = "config1"
    location          = "eastus"
    subnet            = "services"
    availability_zone = 1
    vm_size           = "Standard_F2s_v2"
    hdd_size          = 30
  }
}

module "configserver_vm" {
  for_each = var.configserver

  source         = "../../../terraform/modules/azure-linux-vm"
  resource_group = module.resource_group.name
  ssh_public_key = var.ssh_public_key
  tags           = var.tags
  vm_name            = each.value.name
  location           = each.value.location
  subnet_id          = each.value.subnet
  availability-zones = each.value.availability_zone
  vm_size            = each.value.vm_size
  hdd-size           = each.value.hdd_size
  nsg_id             = module.configserver_nsg[each.value.name].nsg_id
}

resource "azurerm_network_security_rule" "configserver_nsg" {
  for_each = var.configserver
  name              = "Office",
  priority          = "100"
  direction         = "Inbound"
  access            = "Allow"
  protocol          = "TCP"
  source_port_range = "*"
  destination_port_ranges = ["22"]
  source_address_prefix = "192.168.1.100"
  destination_address_prefixes = [
    module.configserver_vm[each.key].private_ip
  ]
  resource_group_name         = var.resource_group_name
  network_security_group_name = "${each.value.name}-nsg"
}

推荐阅读