Azure虚拟网络创建的幂等性问题:避免误删在用子网
问题描述
在Azure上使用Bicep搭建基础设施时,通过以下模块创建虚拟网络(VNet):
param location string param virtualNetworkName string resource virtualNetwork 'Microsoft.Network/virtualNetworks@2019-11-01' = { name: virtualNetworkName location: location properties: { addressSpace: { addressPrefixes: [ '10.0.0.0/16' ] } } }
主Bicep文件调用该模块的代码如下:
module createCommonVirtualNetwok 'modules/createVirtualNetwork.bicep' = { name: 'createCommonVirtualNetwokModule' scope: resourceGroup(commonResourceGroupName) dependsOn: [ createResourceGroupModule_common ] params:{ virtualNetworkName: commonVNetName location: location } }
首次部署成功创建VNet后,通过另一个模块为该VNet添加了子网,且已有容器应用在使用该子网。再次运行部署脚本时,VNet创建模块报错:
Subnet my-subnet is in use by /subscriptions/<mysubid>/resourceGroups/MC_<some-resourcegroup>/providers/Microsoft.Network/networkInterfaces/|providers|Microsoft.Compute|virtualMachineScaleSets|aks-agentpool-<someid>-vmss|virtualMachines|3|networkInterfaces|aks-agentpool-<someid>-vmss/ipConfigurations/ipconfig1 and cannot be deleted. In order to delete the subnet, delete all the resources within the subnet. See aka.ms/deletesubnet.
问题根源在于Bicep的声明式部署模型:模块中未定义子网,Azure会尝试将VNet的子网配置重置为空(即删除现有子网),但子网正在被资源占用,因此报错。需要实现“VNet不存在则创建,存在则保留所有已有的子资源”的效果。
解决方案
方案1:使用@ignoreChanges忽略子网变更(推荐)
在VNet模块的资源定义上添加@ignoreChanges装饰器,明确告诉Bicep忽略子网属性的变化,这样部署时只会维护VNet的核心属性(地址空间、位置),不会修改或删除已有的子网。
修改后的VNet模块代码:
param location string param virtualNetworkName string // 忽略子网属性的变更,避免删除已存在的子网 @ignoreChanges(['properties.subnets']) resource virtualNetwork 'Microsoft.Network/virtualNetworks@2019-11-01' = { name: virtualNetworkName location: location properties: { addressSpace: { addressPrefixes: [ '10.0.0.0/16' ] } } }
后续部署时,Bicep会跳过对子网的检查和修改,仅确保VNet的地址空间和位置符合定义。如果需要忽略其他属性,可将属性名添加到@ignoreChanges的数组中。
方案2:条件部署,仅在VNet不存在时创建
通过判断VNet是否存在,仅在不存在的情况下执行创建模块,彻底避免对已有VNet的修改。
修改主Bicep文件的代码:
param location string param commonResourceGroupName string param commonVNetName string // 检查目标资源组中是否已存在该VNet var vnetExists = !empty(reference(resourceId(commonResourceGroupName, 'Microsoft.Network/virtualNetworks', commonVNetName), '2019-11-01', 'Full').id) // 仅当VNet不存在时执行创建模块 module createCommonVirtualNetwork 'modules/createVirtualNetwork.bicep' = if (!vnetExists) { name: 'createCommonVirtualNetworkModule' scope: resourceGroup(commonResourceGroupName) dependsOn: [ createResourceGroupModule_common ] params: { virtualNetworkName: commonVNetName location: location } } // 可选:引用已存在的VNet,供其他模块使用其属性 resource existingVNet 'Microsoft.Network/virtualNetworks@2019-11-01' existing = { name: commonVNetName scope: resourceGroup(commonResourceGroupName) }
这种方式下,VNet创建完成后,后续部署会跳过该模块,不会对VNet及其子网产生任何影响。
内容的提问来源于stack exchange,提问作者epeleg
相关产品推荐
相关产品推荐

