如何避免Terraform误删Azure虚拟网络中新增的子网资源
解决Terraform重复执行时删除Databricks新增子网的问题
问题描述
我有两个Terraform脚本:一个用于创建带虚拟网络和1个子网的Azure VM;另一个用于创建Databricks,并在该Azure VM的虚拟网络中添加2个子网,以实现Databricks与VM的连通。首次执行terraform apply后一切正常,但再次执行时,Terraform试图删除这2个新增子网。
VM创建网络及子网的代码
resource "azurerm_virtual_network" "neo4j_virt_network" { name = "neo4j-virtnetwork-${var.env}-${var.location}-001" address_space = ["10.0.0.0/16"] location = var.location resource_group_name = var.resource_group subnet { name = "neo4j-virtnetwork-subnet-${var.env}-${var.location}-001" address_prefix = "10.0.1.0/24" security_group = azurerm_network_security_group.neo4j_sg.id } tags = local.tags }
Databricks创建2个新增子网的代码
resource "azurerm_subnet" "private" { name = "databricks-dev-northeurope-001-private" resource_group_name = var.resource_group virtual_network_name = azurerm_virtual_network.neo4j_virt_network.name address_prefixes = ["10.0.3.0/24"] delegation { name = "databricks-delegation" service_delegation { name = "Microsoft.Databricks/workspaces" actions = [ "Microsoft.Network/virtualNetworks/subnets/join/action", "Microsoft.Network/virtualNetworks/subnets/prepareNetworkPolicies/action", "Microsoft.Network/virtualNetworks/subnets/unprepareNetworkPolicies/action", ] } } } resource "azurerm_network_security_group" "private" { name = "databricks-dev-northeurope-001-private-sg" resource_group_name = var.resource_group location = var.location } resource "azurerm_subnet_network_security_group_association" "private" { subnet_id = azurerm_subnet.private.id network_security_group_id = azurerm_network_security_group.private.id } resource "azurerm_subnet" "public" { name = "databricks-dev-northeurope-001-public" resource_group_name = var.resource_group virtual_network_name = azurerm_virtual_network.neo4j_virt_network.name address_prefixes = ["10.0.5.0/24"] delegation { name = "databricks-delegation" service_delegation { name = "Microsoft.Databricks/workspaces" actions = [ "Microsoft.Network/virtualNetworks/subnets/join/action", "Microsoft.Network/virtualNetworks/subnets/prepareNetworkPolicies/action", "Microsoft.Network/virtualNetworks/subnets/unprepareNetworkPolicies/action", ] } } } resource "azurerm_network_security_group" "public" { name = "databricks-dev-northeurope-001-public-sg" resource_group_name = var.resource_group location = var.location } resource "azurerm_subnet_network_security_group_association" "public" { subnet_id = azurerm_subnet.public.id network_security_group_id = azurerm_network_security_group.public.id } resource "azurerm_databricks_workspace" "databricks" { name = "databricks-${var.env}-${var.location}-001" resource_group_name = var.resource_group location = var.location sku = "standard" managed_resource_group_name = "${var.company_name}-rg-databricks-workspace-${var.env}-${var.location}-001" custom_parameters { machine_learning_workspace_id = azurerm_machine_learning_workspace.ml_workspace.id storage_account_name = "databrick${var.env}${random_string.db_code.result}" virtual_network_id = azurerm_virtual_network.neo4j_virt_network.id public_subnet_name = azurerm_subnet.public.name public_subnet_network_security_group_association_id = azurerm_subnet_network_security_group_association.public.id private_subnet_name = azurerm_subnet.private.name private_subnet_network_security_group_association_id = azurerm_subnet_network_security_group_association.private.id } depends_on = [ azurerm_subnet_network_security_group_association.public, azurerm_subnet_network_security_group_association.private, ] tags = local.tags }
调试日志
2022-11-10T09:28:12.050+0200 [WARN] Provider "registry.terraform.io/hashicorp/azurerm" produced an unexpected new value for module.dev.azurerm_virtual_network.neo4j_virt_network during refresh. - .subnet: actual set element cty.ObjectVal(map[string]cty.Value{"address_prefix":cty.StringVal("10.0.3.0/24"), "id":cty.StringVal("[...]"), "name":cty.StringVal("databricks-dev-northeurope-001-private"), "security_group":cty.StringVal("[...]")) does not correlate with any element in plan - .subnet: actual set element cty.ObjectVal(map[string]cty.Value{"address_prefix":cty.StringVal("10.0.5.0/24"), "id":cty.StringVal("[...]"), "name":cty.StringVal("databricks-dev-northeurope-001-public"), "security_group":cty.StringVal("[...]")) does not correlate with any element in plan - .subnet: length changed from 1 to 3
问题原因
核心矛盾在于Terraform对Azure虚拟网络子网的声明式管理逻辑:
- 你在
azurerm_virtual_network.neo4j_virt_network资源内通过嵌套的subnet块定义了VM子网,Terraform会将这个嵌套块视为该虚拟网络下所有子网的完整清单。 - 当通过独立的
azurerm_subnet资源添加Databricks子网后,Terraform刷新状态时发现实际子网数量(3个)与代码定义的嵌套子网数量(1个)不匹配,因此会试图删除额外的两个子网,以让资源状态与代码定义一致。
解决方案
方法1:统一使用独立子网资源声明
将虚拟网络内的嵌套子网块移除,改用独立的azurerm_subnet资源定义VM子网,与Databricks子网保持一致的声明方式:
resource "azurerm_virtual_network" "neo4j_virt_network" { name = "neo4j-virtnetwork-${var.env}-${var.location}-001" address_space = ["10.0.0.0/16"] location = var.location resource_group_name = var.resource_group tags = local.tags } # 原嵌套子网改为独立资源 resource "azurerm_subnet" "neo4j" { name = "neo4j-virtnetwork-subnet-${var.env}-${var.location}-001" resource_group_name = var.resource_group virtual_network_name = azurerm_virtual_network.neo4j_virt_network.name address_prefixes = ["10.0.1.0/24"] security_group = azurerm_network_security_group.neo4j_sg.id }
此方法让所有子网都通过独立资源管理,Terraform会分别跟踪每个子网的状态,不会再试图删除Databricks的子网。
方法2:忽略虚拟网络的子网变化
如果不想修改原有嵌套子网的声明方式,可在虚拟网络资源中添加lifecycle块,让Terraform忽略子网属性的变化:
resource "azurerm_virtual_network" "neo4j_virt_network" { name = "neo4j-virtnetwork-${var.env}-${var.location}-001" address_space = ["10.0.0.0/16"] location = var.location resource_group_name = var.resource_group subnet { name = "neo4j-virtnetwork-subnet-${var.env}-${var.location}-001" address_prefix = "10.0.1.0/24" security_group = azurerm_network_security_group.neo4j_sg.id } tags = local.tags lifecycle { ignore_changes = [subnet] } }
该方法会让Terraform不再检查虚拟网络的子网列表是否与代码一致,从而保留新增的Databricks子网。但注意:后续若需要修改原VM子网的配置,需手动处理,因为Terraform会忽略该属性的所有变化。
验证步骤
修改代码后,执行terraform plan检查是否还会出现删除子网的计划,确认无误后执行terraform apply即可。
内容的提问来源于stack exchange,提问作者Vasyl Stepulo
相关产品推荐
相关产品推荐

