You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Terraform中用for_each循环关联网卡与LB后端池的问题求助

问题描述

需求

  • app-poc-1-nic、app-poc-2-nic 关联至 app-lb 后端池
  • db-nic-1-1-nic、db-nic-1-2-nic 关联至 db-lb 后端池

本地配置块(local)

locals {
  vms = {
    nodes = {
      app_node1 = {
        "vm_name" = "app-poc"
        "vm_num"  = "1"
        networks = {
          nic1 = {
            "vm_name" = "app-poc"
            "subnet"  = "/subscriptions/*****/subnets/app"
          },
        }
      },
      app_node2 = {
        "vm_name" = "app-poc"
        "vm_num"  = "2"
        networks = {
          nic1 = {
            "vm_name" = "app-poc"
            "subnet"  = "/subscriptions/*****/subnets/app"
          },
        }
      },
      service_node1 = {
        "vm_name" = "service-poc"
        "vm_num"  = "1"
        networks = {
          nic1 = {
            "vm_name" = "service-poc"
            "subnet"  = "/subscriptions/*****/subnets/app"
          },
        }
      },
      service_node2 = {
        "vm_name" = "service-poc"
        "vm_num"  = "2"
        networks = {
          nic1 = {
            "vm_name" = "service-poc"
            "subnet"  = "/subscriptions/*****/subnets/app"
          },
        }
      },
      db_node1 = {
        "vm_name" = "db-poc"
        "vm_num"  = "1"
        networks = {
          nic1 = {
            "vm_name" = "db-nic-1"
            "subnet"  = "/subscriptions/*****/subnets/app"
          },
          nic2 = {
            "vm_name" = "db-nic-2"
            "subnet"  = "/subscriptions/*****/subnets/db"
          }
        }
      },
      db_node2 = {
        "vm_name" = "db-poc"
        "vm_num"  = "2"
        networks = {
          nic1 = {
            "vm_name" = "db-nic-1"
            "subnet"  = "/subscriptions/*****/subnets/app"
          },
          nic2 = {
            "vm_name" = "db-nic-2"
            "subnet"  = "/subscriptions/*****/subnets/app"
          },
        }
      },
    },
  }
  lbs = {
    tiers = {
        app-lb = {
          lb_name           = "app-lb"
          fip_name          = "app-fip"
          subnet_id         = "/subscriptions/*****/subnets/app"
          private_ip_type   = "Dynamic"
          address_pool_name = "app-address-pool"
          lb_probes = {
            ssh_probe = {
              protocol = "Tcp"
              port     = "22"
            }
          }
          lb_rules = {
            ssh_rule = {
              frontend_port           = "22"
              protocol                = "Tcp"
              backend_port            = "22"
              enable_floating_ip      = true
              frontend_ip_config_name = "app-fip"
            }
          }
        },
        db-lb = {
          lb_name           = "db-lb"
          fip_name          = "db-fip"
          subnet_id         = "/subscriptions/*****/subnets/app"
          private_ip_type   = "Dynamic"
          address_pool_name = "db-address-pool"
          lb_probes = {
            ssh_probe = {
              protocol = "Tcp"
              port     = "22"
            }
          }
          lb_rules = {
            ssh_rule = {
              frontend_port           = "22"
              protocol                = "Tcp"
              backend_port            = "22"
              enable_floating_ip      = false
              frontend_ip_config_name = "db-fip"
            }
          }
        }
    }
  }
}

已实现的Terraform资源代码

data "azurerm_resource_group" "rg" {
  name = "test-rg"
}
resource "azurerm_network_interface" "nic-poc" {
  for_each = {
    for vm in flatten([
      for vm_name, vm in local.vms.nodes : [
        for nic_name, nic in vm.networks : {
          vm_number    = vm.vm_num,
          vm_name      = vm_name,
          nic_value    = nic.vm_name,
          subnet_value = nic.subnet
          nic_name     = nic_name
        }
      ]
      ]
    ) : "${vm.vm_name}-${vm.nic_name}" => vm
  }
  name                = "${each.value.nic_value}-${each.value.vm_number}-nic"
  location            = data.azurerm_resource_group.rg.location
  resource_group_name = data.azurerm_resource_group.rg.name
  ip_configuration {
    name                          = "${each.value.nic_name}-${each.value.vm_number}-ipconfig"
    subnet_id                     = each.value.subnet_value
    private_ip_address_allocation = "Dynamic"
  }
}

resource "azurerm_linux_virtual_machine" "vm-poc" {
  depends_on                      = [ azurerm_network_interface.nic-poc]
  for_each                        = local.vms.nodes
  name                            = "${each.value.vm_name}-${each.value.vm_num}"
  admin_username                  = "test-admin"
  admin_password                  = "password@29"
  disable_password_authentication = false
  location                        = data.azurerm_resource_group.rg.location
  resource_group_name             = data.azurerm_resource_group.rg.name
  network_interface_ids           = [for nic_key, nic in azurerm_network_interface.nic-poc : nic.id if startswith(nic_key, "${each.key}-")]

  size                = "Standard_B2ms"
  identity {
    type = "SystemAssigned"
  }
  os_disk {
    name                 = "${each.value.vm_name}-${each.value.vm_num}-OSdisk"
    caching              = "ReadWrite"
    storage_account_type = "Standard_LRS"
  }
  source_image_reference {
    publisher = "RedHat"
    offer     = "RHEL"
    sku       = "82gen2"
    version   = "latest"
  }
}

resource "azurerm_lb" "lb" {
  for_each            = local.lbs.tiers
  name                = each.value.lb_name
  location            = data.azurerm_resource_group.rg.location
  resource_group_name = data.azurerm_resource_group.rg.name
  sku                 = "Standard"

  frontend_ip_configuration {
    name                          = each.value.fip_name
    subnet_id                     = each.value.subnet_id
    private_ip_address_allocation = each.value.private_ip_type
  }
}

resource "azurerm_lb_backend_address_pool" "bepool" {
  for_each        = local.lbs.tiers
  loadbalancer_id = azurerm_lb.lb[each.key].id
  name            = each.value.address_pool_name
}


resource "azurerm_lb_probe" "probe" {
  for_each = { for lb, details in local.lbs.tiers : lb => details.lb_probes }

  loadbalancer_id = azurerm_lb.lb[each.key].id
  name            = "ssh-probe"
  protocol        = each.value["ssh_probe"].protocol
  port            = each.value["ssh_probe"].port

}


resource "azurerm_lb_rule" "rule" {
  for_each = { for lb, details in local.lbs.tiers : lb => details.lb_rules }

  loadbalancer_id                = azurerm_lb.lb[each.key].id
  name                           = "ssh-rule"
  protocol                       = each.value["ssh_rule"].protocol
  frontend_port                  = each.value["ssh_rule"].frontend_port
  backend_port                   = each.value["ssh_rule"].backend_port
  frontend_ip_configuration_name = azurerm_lb.lb[each.key].frontend_ip_configuration[0].name
  enable_floating_ip             = each.value["ssh_rule"].enable_floating_ip
  backend_address_pool_ids       = [azurerm_lb_backend_address_pool.bepool[each.key].id]
  probe_id                       = azurerm_lb_probe.probe[each.key].id
}

问题代码及报错

关联资源代码

resource "azurerm_network_interface_backend_address_pool_association" "pool1-1" {
  for_each                    = local.vms.nodes
  network_interface_id        = [for nic_key, nic in azurerm_network_interface.nic-poc : nic.id if startswith(nic_key, "${each.key}-")]
  ip_configuration_name       = [for nic_key, nic in azurerm_network_interface.nic-poc : nic.ip_configuration.name if startswith(nic_key, "${each.key}-")]
  backend_address_pool_id     = azurerm_lb_backend_address_pool.bepool[each.key].id
}

报错信息

1. 索引无效错误

Error: Invalid index
│
│ on main.tf line 238, in resource "azurerm_network_interface_backend_address_pool_association" "pool1-1":
│ 238: backend_address_pool_id = azurerm_lb_backend_address_pool.bepool[each.key].id
│ ├────────────────
│ │ azurerm_lb_backend_address_pool.bepool is object with 2 attributes
│ │ each.key is "db_node2"
│
│ The given key does not identify an element in this collection value.

2. 属性类型错误

Error: Incorrect attribute value type
│
│ on main.tf line 340, in resource "azurerm_network_interface_backend_address_pool_association" "pool1-1":
│ 340: network_interface_id = [for nic_key, nic in azurerm_network_interface.nic-poc : nic.id if startswith(nic_key, "${each.key}-")]
│ ├────────────────
│ │ azurerm_network_interface.nic-poc is object with 8 attributes
│ │ each.key is "service_node1"
│
│ Inappropriate value for attribute "network_interface_id": string required.

Error: Incorrect attribute value type
│
│ on main.tf line 341, in resource "azurerm_network_interface_backend_address_pool_association" "pool1-1":
│ 341: ip_configuration_name = [for nic_key, nic in azurerm_network_interface.nic-poc : nic.ip_configuration.name if startswith(nic_key, "${each.key}-")]
│ ├────────────────
│ │ azurerm_network_interface.nic-poc is object with 8 attributes
│ │ each.key is "service_node2"
│
│ Inappropriate value for attribute "ip_configuration_name": string required.

3. 尝试调整后的报错

│ Error: Invalid index
│
│ on main.tf line 199, in resource "azurerm_network_interface_backend_address_pool_association" "nic_lb_association":
│ 199: ip_configuration_name = azurerm_network_interface.nic-poc[each.key].ip_configuration[0].name
│ ├────────────────
│ │ azurerm_network_interface.nic-poc is object with 8 attributes
│ │ each.key is "db_node1"
│
│ The given key does not identify an element in this collection value.

解决方案

问题分析

  1. 索引无效错误:azurerm_lb_backend_address_pool.bepool的键是app-lb和db-lb,但代码用local.vms.nodes的键(如db_node2)索引,两者不匹配,导致找不到对应元素。
  2. 属性类型错误:network_interface_id和ip_configuration_name要求字符串类型,但代码返回列表,类型不匹配。
  3. 调整后的索引错误:azurerm_network_interface.nic-poc的键是${vm_name}-${nic_name}格式(如db_node1-nic1),直接用db_node1作为键索引找不到对应资源。

正确实现代码

先创建本地映射,明确网卡与后端池的对应关系:

locals {
  nic_lb_associations = {
    # app网卡关联app-lb
    "app-poc-1-nic" = "app-lb"
    "app-poc-2-nic" = "app-lb"
    # db网卡关联db-lb
    "db-nic-1-1-nic" = "db-lb"
    "db-nic-1-2-nic" = "db-lb"
  }
}

再基于映射创建关联资源:

resource "azurerm_network_interface_backend_address_pool_association" "nic_lb_assoc" {
  for_each = local.nic_lb_associations

  # 根据网卡名称匹配对应的nic资源ID
  network_interface_id = [for nic in azurerm_network_interface.nic-poc : nic.id if nic.name == each.key][0]
  # 取网卡的第一个IP配置名称(你的网卡均只有一个IP配置)
  ip_configuration_name = [for nic in azurerm_network_interface.nic-poc : nic.ip_configuration[0].name if nic.name == each.key][0]
  # 根据映射的后端池名称匹配对应ID
  backend_address_pool_id = azurerm_lb_backend_address_pool.bepool[each.value].id
}

优化方案(自动推导关联)

如果不想硬编码网卡名称,可通过本地配置自动生成关联映射:

locals {
  nic_lb_associations = merge(
    # 匹配app开头的网卡,关联app-lb
    { for nic in azurerm_network_interface.nic-poc : nic.name => "app-lb" if startsWith(nic.name, "app-poc-") },
    # 匹配db-nic-1开头的网卡,关联db-lb
    { for nic in azurerm_network_interface.nic-poc : nic.name => "db-lb" if startsWith(nic.name, "db-nic-1-") }
  )
}

resource "azurerm_network_interface_backend_address_pool_association" "nic_lb_assoc" {
  for_each = local.nic_lb_associations

  # 根据网卡名称找到对应的nic资源键
  nic_key = [for k, v in azurerm_network_interface.nic-poc : k if v.name == each.key][0]
  
  network_interface_id    = azurerm_network_interface.nic-poc[nic_key].id
  ip_configuration_name   = azurerm_network_interface.nic-poc[nic_key].ip_configuration[0].name
  backend_address_pool_id = azurerm_lb_backend_address_pool.bepool[each.value].id
}

内容的提问来源于stack exchange,提问作者Uday Kiran

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 18:12:04