Terraform Azure中azurerm_lb_backend_address_pool引发资源重建问题求助
解决Azure Terraform中azurerm_lb_backend_address_pool_address强制重建问题
在Azure Terraform执行plan时,azurerm_lb_backend_address_pool数据块输出显示“known after apply”,导致azurerm_lb_backend_address_pool_address资源被强制重建,无法定位问题根源。代码用于创建负载均衡器、LB规则、探测及后端池等组件,问题集中在以下代码块,尝试获取数据块输出也始终显示“known after apply”。期望执行plan时无变更提示。
当前问题输出
# module.load_balancer.azurerm_lb_backend_address_pool_address.bap_address["3"] must be replaced -/+ resource "azurerm_lb_backend_address_pool_address" "bap_address" { ~ id = "/subscriptions/subscription_id/resourceGroups/rg-smartops-prod-att-appaccess-prod-nx01/providers/Microsoft.Network/loadBalancers/lb_name/backendAddressPools/pool_name/addresses/xxxxx-xx-yyyy" -> (known after apply) ~ inbound_nat_rule_port_mapping = [] -> (known after apply) ~ name = "xxxxx-xx-xxx-yyyyy" -> (known after apply) # forces replacement # (3 unchanged attributes hidden) }
相关代码
locals { backend_pool_add = flatten([ for lb in var.load_balancer: [ for vm in lb.backend_pool: [ for ip in vm.ip_address: { lb_name = lb.lb_name backend_address_pool_name = vm.backend_address_pool_name ip_address = ip nic_name = vm.ip_address != null ? "nic" : null } ] if vm.vm_nic_name == null ] ]) backend_pool_add_ori = flatten([ for lb in var.load_balancer: [ for vm in lb.backend_pool: { lb_name = lb.lb_name backend_address_pool_name = vm.backend_address_pool_name nic_name = vm.ip_address != null ? "nic" : null } if vm.vm_nic_name == null ] ]) } data "azurerm_lb_backend_address_pool" "bap_pool_ipname_ori" { for_each = { for bap in local.backend_pool_add_ori : "${bap.backend_address_pool_name}-${bap.lb_name}" => bap if bap.nic_name != null} name = each.value.backend_address_pool_name loadbalancer_id = azurerm_lb.lb[each.value.lb_name].id } resource "azurerm_lb_backend_address_pool_address" "bap_address" { for_each = { for idx , bp in local.backend_pool_add : idx => bp if bp.nic_name != null} name = data.azurerm_lb_backend_address_pool.bap_pool_ipname_ori["${each.value.backend_address_pool_name}-${each.value.lb_name}"].backend_address[each.key % 2].name backend_address_pool_id = azurerm_lb_backend_address_pool.bap_pool_ip[each.value.ip_address].id virtual_network_id = data.azurerm_virtual_network.vnet_backend_address_pool[each.value.lb_name].id ip_address = each.value.ip_address depends_on = [ azurerm_lb.lb, azurerm_lb_backend_address_pool.bap_pool_ip] }
问题根源分析
name字段依赖动态计算值:azurerm_lb_backend_address_pool_address的name属性引用了数据块的动态输出值,而该数据块依赖正在创建的azurerm_lb.lb资源,导致name始终无法在plan阶段确定,触发资源重建。- for_each使用不稳定索引:
bap_address的for_each用数组索引作为键,当local.backend_pool_add元素顺序变化时,会导致资源键值变更,间接引发重建。 - 数据块与资源块依赖冲突:如果
azurerm_lb.lb是当前Terraform代码创建的,使用data块查询其属性必然会返回“known after apply”,因为资源尚未创建完成。
修复方案
方案1:使用静态可预测的name值
直接通过后端池名称和IP地址生成静态name,同时修改for_each为稳定唯一的键值:
resource "azurerm_lb_backend_address_pool_address" "bap_address" { # 用LB名称、后端池名称、IP地址组合成唯一稳定的键 for_each = { for bp in local.backend_pool_add : "${bp.lb_name}-${bp.backend_address_pool_name}-${bp.ip_address}" => bp if bp.nic_name != null} # 基于IP地址生成静态名称,替换点号避免非法字符 name = "${each.value.backend_address_pool_name}-${replace(each.value.ip_address, ".", "-")}" backend_address_pool_id = azurerm_lb_backend_address_pool.bap_pool_ip[each.value.ip_address].id virtual_network_id = data.azurerm_virtual_network.vnet_backend_address_pool[each.value.lb_name].id ip_address = each.value.ip_address depends_on = [ azurerm_lb.lb, azurerm_lb_backend_address_pool.bap_pool_ip] }
方案2:移除不必要的数据块
如果azurerm_lb_backend_address_pool是当前代码创建的(即azurerm_lb_backend_address_pool.bap_pool_ip),直接引用该资源属性即可,无需使用data块查询:
# 删除原有的data "azurerm_lb_backend_address_pool" "bap_pool_ipname_ori"块 resource "azurerm_lb_backend_address_pool_address" "bap_address" { for_each = { for bp in local.backend_pool_add : "${bp.lb_name}-${bp.backend_address_pool_name}-${bp.ip_address}" => bp if bp.nic_name != null} name = "${each.value.backend_address_pool_name}-${replace(each.value.ip_address, ".", "-")}" backend_address_pool_id = azurerm_lb_backend_address_pool.bap_pool_ip[each.value.ip_address].id virtual_network_id = data.azurerm_virtual_network.vnet_backend_address_pool[each.value.lb_name].id ip_address = each.value.ip_address depends_on = [ azurerm_lb.lb, azurerm_lb_backend_address_pool.bap_pool_ip] }
方案3:确保数据块依赖已存在资源
如果必须使用data块,需保证azurerm_lb.lb是已存在的资源(非当前Terraform代码创建),否则Terraform无法提前获取其属性值。若LB是当前代码创建的,必须直接引用资源属性而非数据块。
内容的提问来源于stack exchange,提问作者Maya Ray
相关产品推荐
相关产品推荐

