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

Terraform for_each循环下Azure VM数据磁盘创建与挂载问题

问题修复与实现方案

核心问题分析

  • azurerm_managed_disk.data 资源块存在重复定义的语法错误,且未处理多数据盘场景(vm_data_disk_count 参数)
  • 磁盘附件资源中,managed_disk_id 引用方式错误(直接使用列表而非对应磁盘ID),virtual_machine_id 引用路径错误
  • 未建立虚拟机与对应数据盘的关联映射

修正后的代码实现

1. 定义本地变量展开VM与数据盘的映射

通过locals将每个VM的多数据盘展开为独立条目,为后续资源关联提供清晰的映射关系:

locals {
  # 展开每个VM的数据盘,生成包含VM标识、磁盘索引的结构化数据
  vm_data_disks = flatten([
    for vm_key, vm in var.spark_vms : [
      for disk_idx in range(vm.vm_data_disk_count) : {
        vm_key     = vm_key
        disk_index = disk_idx
        vm_name    = vm.vm_name
        disk_size  = vm.vm_data_disk_size
        disk_type  = vm.vm_data_disk_type
      }
    ]
  ])

  # 为每个数据盘生成唯一的for_each键(格式:vm_key-disk_index),保证资源标识稳定
  vm_data_disk_keys = {
    for disk in local.vm_data_disks : "${disk.vm_key}-${disk.disk_index}" => disk
  }
}

2. 修正数据盘资源定义

使用展开后的local.vm_data_disk_keys作为for_each数据源,确保每个数据盘独立创建:

resource "azurerm_managed_disk" "data" {
  for_each             = local.vm_data_disk_keys
  name                 = "${each.value.vm_name}-DataDisk--%02d" % each.value.disk_index
  location             = var.location
  resource_group_name  = var.iaas_rg_name
  storage_account_type = each.value.disk_type
  create_option        = "Empty"
  disk_size_gb         = each.value.disk_size
  tags                 = var.spark_vm_tags
}

3. 修正磁盘附件资源定义

关联对应虚拟机和数据盘,确保每个附件绑定正确的实例:

resource "azurerm_virtual_machine_data_disk_attachment" "data" {
  for_each           = local.vm_data_disk_keys
  managed_disk_id    = azurerm_managed_disk.data[each.key].id
  virtual_machine_id = azurerm_virtual_machine.spark-linux[each.value.vm_key].id
  lun                = 10 + each.value.disk_index # 从10开始递增LUN,避免与系统预留LUN冲突
  caching            = "ReadWrite"
}

4. 保留并校验原虚拟机资源

确保虚拟机资源的网络接口引用正确(需保证azurerm_network_interface.spark-nic同样使用for_each = var.spark_vms定义):

resource "azurerm_virtual_machine" "spark-linux" {
  for_each              = var.spark_vms
  name                  = each.value.vm_name
  location              = var.location
  resource_group_name   = var.iaas_rg_name
  network_interface_ids = [azurerm_network_interface.spark-nic[each.key].id]
  vm_size               = each.value.vm_size
  availability_set_id   = azurerm_availability_set.spark_av_set.id
  tags                  = merge(var.base_tags, var.spark_vm_tags)

  identity {
    type = "SystemAssigned"
  }

  boot_diagnostics {
    enabled     = true
    storage_uri = "" # 此处需填写有效的存储账户URI,否则Terraform会抛出错误
  }

  storage_os_disk {
    name              = "${each.value.vm_name}-osDisk"
    caching           = "ReadWrite"
    create_option     = "FromImage"
    managed_disk_type = var.prem_os_managed_disk_type
  }

  os_profile {
    computer_name  = each.value.vm_name
    admin_username = var.admin_username
    admin_password = var.admin_password
  }

  storage_image_reference {
    publisher = var.linux_publisher
    offer     = var.linux_offer
    sku       = var.linux_sku
    version   = var.linux_os_version
  }

  os_profile_linux_config {
    disable_password_authentication = false
  }

  delete_os_disk_on_termination    = true
  delete_data_disks_on_termination = true
}

关键说明

  • 用flatten+嵌套for循环处理多数据盘场景,将每个VM的N个数据盘转换为独立资源条目
  • 以vm_key-disk_index作为唯一标识,保证for_each的稳定性,避免因数据顺序变更导致资源重建
  • LUN值从10开始递增,规避系统预留LUN的冲突问题
  • 修复了磁盘ID与VM ID的引用错误,确保每个磁盘附件关联正确的虚拟机和数据盘

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 19:54:53