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

Terraform嵌套for_each使用应用时未知值报错求助

Terraform for_each 未知值错误解决方案

问题场景

作为Terraform新手,我正在搭建测试项目:创建4台VM,部署Application Gateway并将VM划分到两个后端池,实现基于URL路径的路由。为关联VM模块输出的网卡ID与对应后端池,我在locals.tf中通过嵌套for循环生成了包含VM、后端池及网卡信息的映射列表,但将其作为azurerm_network_interface_application_gateway_backend_address_pool_association资源的for_each值时,触发以下错误:

The "for_each" set includes values derived from resource attributes that cannot be determined until apply, and so Terraform cannot determine the full set of keys that will identify the instances of this resource.
When working with unknown values in for_each, it's better to use a map value where the keys are defined statically in your configuration and where only the values contain apply-time results.
Alternatively, you could use the -target planning option to first apply only the resources that the for_each value depends on, and then apply a second time to fully converge.

我不想使用-target分步部署,需要可行的解决办法。

问题原因

当前local.backend_nics是列表类型,且列表元素包含大量apply阶段才能生成的属性(比如网卡ID、IP配置名称)。Terraform的for_each要求提前确定所有实例的唯一标识:

  • 列表的索引是动态的,且元素值存在未知项时,Terraform无法提前确认实例集合
  • 必须使用**映射(map)**类型,且映射的键是静态可预测的字符串,仅值包含apply阶段的动态属性

解决方案

将local.backend_nics从列表转换为以静态唯一键为索引的映射,键由后端池标识和VM名称组合而成(两者都是提前定义的静态值),确保Terraform在plan阶段就能确定所有实例的键。

1. 修改locals定义

将嵌套for循环生成的列表改为映射,用"${poolkey}-${nickey}"作为唯一键:

locals {
  backend_nics = {
    for poolkey, poolvalues in var.backend_pools :
    for nickey, nicvalues in var.imported_nics :
    "${poolkey}-${nickey}" => {
      pool_key = poolkey
      nic_key = nickey
      be_pool_name = poolvalues.bep_name
      be_pool_path = poolvalues.bep_path
      vm_nic_name = nicvalues.name
      vm_nic_id = nicvalues.id
      vm_nic_ipconfig_name = nicvalues.ip_configuration[0].name
    } if contains(poolvalues.bep_members, nickey)
  }
}

2. 确保网卡输入为键值映射

VM模块输出的网卡集合需以VM名称为键,这样nickey才能和backend_pools中的bep_members匹配:

  • 若VM模块当前输出是列表,修改输出为映射:
output "vmnics" {
  value = { for nic in azurerm_network_interface.vmnic : nic.name => nic }
}
  • 或在调用Application Gateway模块时转换:
module "app_gateway" {
  # 其他参数...
  imported_nics = { for nic in module.virtual_machines.vmnics : nic.name => nic }
}

3. 保持关联资源的for_each配置

直接使用修改后的映射作为for_each值:

resource "azurerm_network_interface_application_gateway_backend_address_pool_association" "appgwnicassoc01" {
  for_each = local.backend_nics

  backend_address_pool_id = azurerm_application_gateway.appgateway01[each.value.pool_key].backend_address_pool_id
  network_interface_id    = each.value.vm_nic_id
  ip_configuration_name   = each.value.vm_nic_ipconfig_name
}

原理说明

组合键"${poolkey}-${nickey}"由静态定义的后端池标识(如be_pool_01)和VM名称(如appvm01)组成,Terraform在plan阶段就能完整确定所有键的集合,而值中的动态属性(网卡ID等)仅在apply阶段生成,不会影响实例标识的确定性,完全符合for_each的要求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 10:27:03