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

Terraform Azure现有代码新增2个NSG与3个子网配置求助

问题根因

现有代码无法正常新增子网和NSG,核心是3个硬伤:

  • 仅定义了1个NSG、2个子网,且所有NSG规则绑定在同一个NSG上,子网、NSG的关联逻辑写死了单资源引用,不支持扩容
  • 3台虚拟机的网卡配置为单例资源,多台VM共用1块网卡不符合Azure资源逻辑,且network_interface_ids字段错误拼接count.index,会触发类型不匹配报错
  • 同时在子网级别和网卡级别绑定同一个NSG,很容易出现关联冲突,导致Terraform状态漂移

修改方案

1. 子网规划

现有VNet地址段为10.0.0.0/16,在原有2个网段基础上新增第三个网段,3个子网分别做应用子网、数据库子网、管理子网使用,地址段分配:

  • 应用子网:10.0.1.0/24
  • 数据库子网:10.0.2.0/24
  • 管理子网:10.0.3.0/24

2. NSG拆分

新增第二个独立NSG,把原有混在同一个NSG的规则拆分绑定:

  • 应用层NSG:绑定8080入站规则,关联应用子网
  • 数据库层NSG:绑定5432入站规则,限制仅应用子网段可访问,关联数据库子网
  • 移除网卡层面的NSG关联,统一在子网层面做NSG绑定,避免冲突

3. 资源关联修正

  • 用count生成3块独立网卡,分别绑定到应用子网,替代原有单块网卡的错误配置
  • 修正虚拟机资源的网卡ID引用格式
  • 补全PostgreSQL柔性服务器必需的子网参数,将数据库服务部署到数据库子网
  • 统一公网IP、负载均衡的SKU为Standard,避免Basic SKU资源版本不兼容问题

修正后可直接运行的main.tf代码
resource "random_pet" "rg-name" {
  prefix    = var.resource_group_name_prefix
}

resource "azurerm_resource_group" "rg" {
  name      = random_pet.rg-name.id
  location  = var.resource_group_location
}

# 创建虚拟网络
resource "azurerm_virtual_network" "Vnet" {
  name                = "Vnet"
  address_space       = ["10.0.0.0/16"]
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name
}

# 3个子网定义
resource "azurerm_subnet" "app_subnet" {
  name                 = "app-subnet"
  resource_group_name  = azurerm_resource_group.rg.name
  virtual_network_name = azurerm_virtual_network.Vnet.name
  address_prefixes     = ["10.0.1.0/24"]
}

resource "azurerm_subnet" "db_subnet" {
  name                 = "db-subnet"
  resource_group_name  = azurerm_resource_group.rg.name
  virtual_network_name = azurerm_virtual_network.Vnet.name
  address_prefixes     = ["10.0.2.0/24"]
}

resource "azurerm_subnet" "mgmt_subnet" {
  name                 = "mgmt-subnet"
  resource_group_name  = azurerm_resource_group.rg.name
  virtual_network_name = azurerm_virtual_network.Vnet.name
  address_prefixes     = ["10.0.3.0/24"]
}

# 2个独立NSG定义
resource "azurerm_network_security_group" "app_nsg" {
  name                = "app-nsg"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name
}

resource "azurerm_network_security_group" "db_nsg" {
  name                = "db-nsg"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name
}

# 应用NSG规则:允许8080端口入站
resource "azurerm_network_security_rule" "app_port_8080" {
  name                        = "allow-8080-inbound"
  priority                    = 110
  direction                   = "inbound"
  access                      = "Allow"
  protocol                    = "Tcp"
  source_port_range           = "*"
  destination_port_range      = "8080"
  source_address_prefix       = "*"
  destination_address_prefix  = "*"
  resource_group_name         = azurerm_resource_group.rg.name
  network_security_group_name = azurerm_network_security_group.app_nsg.name
}

# 数据库NSG规则:仅允许应用子网访问5432端口
resource "azurerm_network_security_rule" "db_port_5432" {
  name                        = "allow-5432-from-app"
  priority                    = 100
  direction                   = "inbound"
  access                      = "Allow"
  protocol                    = "Tcp"
  source_port_range           = "*"
  destination_port_range      = "5432"
  source_address_prefix       = azurerm_subnet.app_subnet.address_prefixes[0]
  destination_address_prefix  = "*"
  resource_group_name         = azurerm_resource_group.rg.name
  network_security_group_name = azurerm_network_security_group.db_nsg.name
}

# 子网与NSG关联
resource "azurerm_subnet_network_security_group_association" "app_subnet_nsg_bind" {
  subnet_id                 = azurerm_subnet.app_subnet.id
  network_security_group_id = azurerm_network_security_group.app_nsg.id
}

resource "azurerm_subnet_network_security_group_association" "db_subnet_nsg_bind" {
  subnet_id                 = azurerm_subnet.db_subnet.id
  network_security_group_id = azurerm_network_security_group.db_nsg.id
}

# 负载均衡公网IP
resource "azurerm_public_ip" "lb_pub_ip" {
  name                = "lb-public-ip"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name
  allocation_method   = "Static"
  sku                 = "Standard"
}

# 3台应用VM对应独立网卡
resource "azurerm_network_interface" "app_nic" {
  count               = 3
  name                = "app-nic-${count.index}"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name

  ip_configuration {
    name                          = "app-nic-conf-${count.index}"
    subnet_id                     = azurerm_subnet.app_subnet.id
    private_ip_address_allocation = "Dynamic"
  }
}

# 负载均衡
resource "azurerm_lb" "app_lb" {
  name                = "app-loadbalancer"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name
  sku                 = "Standard"

  frontend_ip_configuration {
    name                 = "lb-frontend"
    public_ip_address_id = azurerm_public_ip.lb_pub_ip.id
  }
}

# 3台应用虚拟机
resource "azurerm_virtual_machine" "vm_app" {
  count                 = 3
  name                  = "app_vm${count.index}"
  location              = azurerm_resource_group.rg.location
  resource_group_name   = azurerm_resource_group.rg.name
  network_interface_ids = [azurerm_network_interface.app_nic[count.index].id]
  vm_size               = "Standard_B2s"

  delete_os_disk_on_termination    = true
  delete_data_disks_on_termination = true

  storage_image_reference {
    publisher = "Canonical"
    offer     = "0001-com-ubuntu-server-focal"
    sku       = "20_04-lts-gen2"
    version   = "latest"
  }
  storage_os_disk {
    name              = "app-os-disk-${count.index}"
    caching           = "ReadWrite"
    create_option     = "FromImage"
    managed_disk_type = "Standard_LRS"
  }
}

# 镜像存储资源组
resource "azurerm_resource_group" "Image_App" {
  name     = "Weight_Tracker_application"
  location = "EastUS"
}

# PostgreSQL柔性服务器,部署到数据库子网
resource "azurerm_postgresql_flexible_server" "PS_SQL" {
  name                   = "sqlflexserver"
  resource_group_name    = azurerm_resource_group.rg.name
  location               = azurerm_resource_group.rg.location
  version                = "12"
  administrator_login    = "postgres"
  administrator_password = "p@ssw0rd42"
  storage_mb             = 32768
  sku_name               = "GP_Standard_D4s_v3"
  subnet_id              = azurerm_subnet.db_subnet.id
}

resource "azurerm_postgresql_flexible_server_database" "PS_FLEX" {
  name      = "db-server"
  server_id = azurerm_postgresql_flexible_server.PS_SQL.id
  collation = "en_US.utf8"
  charset   = "utf8"
}

部署校验要点
  • 执行terraform plan时确认资源变更清单包含3个子网、2个NSG,无资源替换报错
  • 数据库NSG默认拒绝公网访问5432端口,如需本地调试可临时加放通规则,上线前务必删除
  • 管理子网默认未绑定NSG,可后续按需配置跳板机相关访问规则

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 23:03:23