Terraform使用for_each批量创建子网遇问题,请求排查
Terraform使用for_each创建子网问题排查
背景
此问题为之前Terraform对象/映射类型值引用问题的延续。
目标
使用Terraform的for_each循环创建子网。
terraform.tfvars.json相关配置
"subnets" : { "Dev" : [ {"gw_snet":{ "name" : "GatewaySubnet", "address_prefixes" : ["10.1.1.0/24"] }, "dns-snet" : { "name" : "InboundDNSSubnet", "address_prefixes" : ["10.1.2.0/24"] }, "common_snet" : { "name" : "Common", "address_prefixes" : ["10.1.3.0/24"] }, "clientdata_snet" : { "name" : "ClientDataSubnet", "address_prefixes" : ["10.1.4.0/20"] }} ], "Stage" : [ {"gw_snet":{ "name" : "GatewaySubnet", "address_prefixes" : ["10.2.1.0/24"] }, "dns-snet" : { "name" : "InboundDNSSubnet", "address_prefixes" : ["10.2.2.0/24"] }, "common_snet" : { "name" : "Common", "address_prefixes" : ["10.2.3.0/24"] }, "clientdata_snet" : { "name" : "ClientDataSubnet", "address_prefixes" : ["10.2.4.0/20"] }} ], "Prod" : [ {"gw_snet":{ "name" : "GatewaySubnet", "address_prefixes" : ["10.3.1.0/24"] }, "dns-snet" : { "name" : "InboundDNSSubnet", "address_prefixes" : ["10.3.2.0/24"] }, "common_snet" : { "name" : "Common", "address_prefixes" : ["10.3.3.0/24"] }, "clientdata_snet" : { "name" : "ClientDataSubnet", "address_prefixes" : ["10.3.4.0/20"] }} ] }
VNet创建代码
resource "azurerm_virtual_network" "vnet" { name = var.hub_vnet_name location = azurerm_resource_group.rg[0].location resource_group_name = azurerm_resource_group.rg[0].name for_each = {for k,v in var.vnet_address_space: k=>v if k == "Dev"} address_space = each.value dns_servers = var.dns_servers tags = { environment = "${var.env}" costcentre = "14500" } dynamic "ddos_protection_plan" { for_each = local.if_ddos_enabled content { id = azurerm_network_ddos_protection_plan.ddos[0].id enable = false } } }
子网创建尝试代码
resource "azurerm_subnet" "mysubnet" { for_each = {for k,v in var.subnets: k=>v if k == "Dev"} name = each.value.name address_prefixes = [each.value.address_prefixes] virtual_network_name = var.hub_vnet_name resource_group_name = var.resource_group_name }
遇到的问题
Terraform plan无报错,但无法创建VNet,计划未通过验证。怀疑子网变量定义存在问题,同时不确定如何正确访问嵌套值,当前的each.value.name和[each.value.address_prefixes]无法正常工作。
问题根源与解决方案
1. 变量结构嵌套过深导致访问失败
var.subnets的结构中,每个环境(如Dev)对应的值是包含单个对象的数组,数组内的对象才是各个子网的键值对集合。当前for_each仅拿到了Dev对应的数组,而数组本身没有name和address_prefixes属性,导致引用失败。
2. 修正方案:扁平化子网结构
先通过locals将嵌套的子网结构扁平化,方便for_each遍历:
locals { flattened_subnets = merge([ for env, subnets_list in var.subnets : { for subnet_key, subnet in subnets_list[0] : "${env}-${subnet_key}" => merge(subnet, { environment = env }) } ]...) }
这个本地值会将所有子网展开为一个映射,键格式为环境-子网标识(如Dev-gw_snet),值包含子网属性及所属环境。
3. 修正子网资源代码
使用扁平化后的本地值,并正确引用VNet资源实例(而非变量):
resource "azurerm_subnet" "mysubnet" { for_each = { for k, v in local.flattened_subnets : k => v if v.environment == "Dev" } name = each.value.name address_prefixes = each.value.address_prefixes virtual_network_name = azurerm_virtual_network.vnet["Dev"].name resource_group_name = azurerm_resource_group.rg[0].name }
4. 修正VNet资源的命名问题
原VNet代码中name = var.hub_vnet_name会导致多环境下重名,需添加环境后缀确保唯一性:
resource "azurerm_virtual_network" "vnet" { for_each = {for k,v in var.vnet_address_space: k=>v if k == "Dev"} name = "${var.hub_vnet_name}-${each.key}" location = azurerm_resource_group.rg[0].location resource_group_name = azurerm_resource_group.rg[0].name address_space = each.value dns_servers = var.dns_servers tags = { environment = each.key costcentre = "14500" } dynamic "ddos_protection_plan" { for_each = local.if_ddos_enabled content { id = azurerm_network_ddos_protection_plan.ddos[0].id enable = false } } }
内容的提问来源于stack exchange,提问作者asp
相关产品推荐
相关产品推荐

