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

如何通过Azapi Network Group Static Members为静态组添加多个成员?

问题描述

我正在学习Terraform,要在Azure中搭建Hub and Spoke网络,同时配置Network Manager,要求使用包含Static Members的Network Group。之前用for_each批量创建Spoke VNet并加入网络组,但现在手动创建了两个独立的VNet(vm-spoke-vnet和aks-spoke-vnet)及子网,不知道怎么把这两个VNet加入同一个静态组。看了微软的基础模板后还是没头绪,以为独立资源没法用for_each(可能这个判断错了),想过加多个Resource ID但不确定是否可行,求最佳实现方法。

基础模板

resource "azapi_resource" "symbolicname" {
  type = "Microsoft.Network/networkManagers/networkGroups/staticMembers@2022-07-01"
  name = "string"
  parent_id = "string"
  body = jsonencode({
    properties = {
      resourceId = "string"
    }
  })
}

旧代码(使用for_each批量创建VNet并加入组)

resource "azurerm_virtual_network" "spokes" {
  for_each            = local.spoke_subnets
  name                = each.key
  resource_group_name = azurerm_resource_group.test.name
  location            = azurerm_resource_group.test.location
  address_space       = each.value.address_space
}

resource "azapi_resource" "network_manager" {
  type      = "Microsoft.Network/networkManagers@2022-07-01"
  name      = "networkmanager"
  parent_id = azurerm_resource_group.test.id
  location  = azurerm_resource_group.test.location

  body = jsonencode({
    properties = {
      networkManagerScopeAccesses = [
        "Connectivity",
        "SecurityAdmin"
      ]
      networkManagerScopes = {
        subscriptions = [
          data.azurerm_subscription.current.id
        ]
      }
    }
  })
}

resource "azapi_resource" "spoke_group" {
  type      = "Microsoft.Network/networkManagers/networkGroups@2022-07-01"
  name      = "spokes"
  parent_id = azapi_resource.network_manager.id

  body = jsonencode({
    properties = {
      memberType = "VirtualNetwork"
    }
  })
}

resource "azapi_resource" "spoke_group_members" {
  type      = "Microsoft.Network/networkManagers/networkGroups/staticMembers@2022-07-01"
  for_each  = azurerm_virtual_network.spokes
  name      = each.value.name
  parent_id = azapi_resource.spoke_group.id

  body = jsonencode({
    properties = {
      resourceId = each.value.id
    }
  })
}

新代码(手动创建独立VNet,需完善组成员配置)

resource "azurerm_virtual_network" "vm-spoke-vnet" {
    name                = "ty-vm-spoke-vnet"
    location            = azurerm_resource_group.test.location
    resource_group_name = azurerm_resource_group.test.name
    address_space       = ["10.1.0.0/16"]

    tags = {
    environment = "hub-spoke"
    }
}
#VNet for AKS Spoke - Not sure if correct
resource "azurerm_virtual_network" "aks-spoke-vnet" {
    name                = "ty-aks-spoke-vnet"
    location            = azurerm_resource_group.test.location
    resource_group_name = azurerm_resource_group.test.name
    address_space       = ["10.2.0.0/16"]

    tags = {
    environment = "hub-spoke"
    }
}
#Subnet for VMs
resource "azurerm_subnet" "vm-spoke-subnet" {
    name                 = "ty-vm-subnet"
    resource_group_name  = azurerm_resource_group.test.name
    virtual_network_name = azurerm_virtual_network.vm-spoke-vnet.name
    address_prefixes     = ["10.1.0.64/27"]
}
#Subnet for AKS - Not sure if correct
resource "azurerm_subnet" "aks-spoke-subnet" {
    name                 = "ty-aks-subnet"
    resource_group_name  = azurerm_resource_group.test.name
    virtual_network_name = azurerm_virtual_network.aks-spoke-vnet.name
    address_prefixes     = ["10.2.0.64/27"]
}
resource "azapi_resource" "network_manager" {
  type      = "Microsoft.Network/networkManagers@2022-07-01"
  name      = "networkmanager"
  parent_id = azurerm_resource_group.test.id
  location  = azurerm_resource_group.test.location

  body = jsonencode({
    properties = {
      networkManagerScopeAccesses = [
        "Connectivity",
        "SecurityAdmin"
      ]
      networkManagerScopes = {
        subscriptions = [
          data.azurerm_subscription.current.id
        ]
      }
    }
  })
}
#Group for all of the Spoke Networks
resource "azapi_resource" "spoke_group" {
  type      = "Microsoft.Network/networkManagers/networkGroups@2022-07-01"
  name      = "spokes"
  parent_id = azapi_resource.network_manager.id

  body = jsonencode({
    properties = {
      memberType = "VirtualNetwork"
    }
  })
}

resource "azapi_resource" "spoke_group_members" {
  type      = "Microsoft.Network/networkManagers/networkGroups/staticMembers@2022-07-01"
  for_each  = azurerm_virtual_network.spokes
  name      = each.value.name
  parent_id = azapi_resource.spoke_group.id

  body = jsonencode({
    properties = {
      resourceId = each.value.id
    }
  })
}
解决方案

方法1:用for_each遍历手动创建的VNet集合

你完全可以继续用for_each,只要把两个独立的VNet放到一个集合里即可。在代码中添加一个本地值,把两个VNet的ID和名称映射进去,然后用for_each遍历这个集合:

# 定义本地集合,包含所有需要加入组的Spoke VNet
locals {
  spoke_vnets = {
    vm_spoke = {
      name = azurerm_virtual_network.vm-spoke-vnet.name
      id   = azurerm_virtual_network.vm-spoke-vnet.id
    }
    aks_spoke = {
      name = azurerm_virtual_network.aks-spoke-vnet.name
      id   = azurerm_virtual_network.aks-spoke-vnet.id
    }
  }
}

# 替换原来的spoke_group_members资源
resource "azapi_resource" "spoke_group_members" {
  type      = "Microsoft.Network/networkManagers/networkGroups/staticMembers@2022-07-01"
  for_each  = local.spoke_vnets
  name      = each.value.name
  parent_id = azapi_resource.spoke_group.id

  body = jsonencode({
    properties = {
      resourceId = each.value.id
    }
  })
}

这种方法保留了for_each的优势,后续新增VNet时只需要在local.spoke_vnets里添加条目即可,不需要重复编写资源块。

方法2:手动创建两个静态成员资源

如果不想用for_each,也可以直接创建两个独立的azapi_resource资源,分别对应两个VNet:

# 加入VM Spoke VNet
resource "azapi_resource" "vm_spoke_static_member" {
  type      = "Microsoft.Network/networkManagers/networkGroups/staticMembers@2022-07-01"
  name      = azurerm_virtual_network.vm-spoke-vnet.name
  parent_id = azapi_resource.spoke_group.id

  body = jsonencode({
    properties = {
      resourceId = azurerm_virtual_network.vm-spoke-vnet.id
    }
  })
}

# 加入AKS Spoke VNet
resource "azapi_resource" "aks_spoke_static_member" {
  type      = "Microsoft.Network/networkManagers/networkGroups/staticMembers@2022-07-01"
  name      = azurerm_virtual_network.aks-spoke-vnet.name
  parent_id = azapi_resource.spoke_group.id

  body = jsonencode({
    properties = {
      resourceId = azurerm_virtual_network.aks-spoke-vnet.id
    }
  })
}

这种方法更直观,但VNet数量多的时候会产生重复代码,维护成本较高。

推荐方案

优先选择方法1,它兼顾了代码简洁性和可维护性,符合Terraform的基础设施即代码最佳实践。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 15:07:59