Terraform从含数据磁盘的Azure通用镜像创建VM报错及恢复方法
问题:使用Terraform从带数据磁盘的Azure通用镜像创建VM时出现400错误
我制作了一个附加独立数据磁盘的Windows虚拟机通用镜像,在Azure门户中可正常创建包含该数据磁盘的资源,但使用Terraform代码创建时出现如下400错误:
Virtual Machine Name: "test-vm"): performing CreateOrUpdate: unexpected status 400 (400 Bad Request) with error: InvalidParameter: StorageProfile.dataDisks.lun does not have required value(s) for image specified in storage profile. │ │ with azurerm_windows_virtual_machine.vm["vm1"], │ on vm.tf line 67, in resource "azurerm_windows_virtual_machine" "vm": │ 67: resource "azurerm_windows_virtual_machine" "vm" {
用户提供的代码
var.tf
############################ ### Location & Network ############################ ### Location variable "location" { type = string default = "Korea Central" } ### Resource Group Valiable - Network variable "network_rg" { type = string default = "test-vm-rg" } ### Virtual Network Valiable variable "network_vnet" { type = string default = "vnet-test-vm" } ### Subnet Valiable variable "network_subnet" { type = string default = "subnet-test-vm" } ### Private IP Setting variable "private-ip-type" { type = string default = "Static" } ############################ ### Resource & OS env ############################ ### Resource Group variable "system_rg" { type = string default = "test-vm-d-rg" } ############################ ### Image Information ############################ ### Image Publisher variable "vm_template" { type = map(any) default = { vm1 = { source_image_id = "/subscriptions/0000000000000/resourceGroups/test-vm-rg/providers/Microsoft.Compute/images/vm-test-vm-image-v1" vm_name = "test-vm" hostname = "test-vm" os_publisher = "MicrosoftWindowsServer" os_offer = "WindowsServer" os_sku = "2022-datacenter-azure-edition" license_type = "Windows_Server" os_version = "latest" osdisk_type = "StandardSSD_LRS" osdisk_size = "128" vm_type = "Standard_D2s_v5" adminid = "testadmin" private_ip = "10.10.10.10" nic = "nic01" os_disk = "osdisk01" } } }
vm.tf
data "azurerm_resource_group" "system_rg_name" { name = var.system_rg } data "azurerm_subnet" "network_subnet" { name = var.network_subnet virtual_network_name = var.network_vnet resource_group_name = var.network_rg } resource "azurerm_network_interface" "nic" { for_each = var.vm_template name = "${each.value.vm_name}-${each.value.nic}" location = var.location resource_group_name = data.azurerm_resource_group.system_rg_name.name accelerated_networking_enabled = true ip_configuration { name = "internal" subnet_id = data.azurerm_subnet.network_subnet.id private_ip_address_allocation = var.private-ip-type private_ip_address = each.value.private_ip } } resource "azurerm_windows_virtual_machine" "vm" { for_each = var.vm_template name = each.value.vm_name location = var.location resource_group_name = data.azurerm_resource_group.system_rg_name.name source_image_id = each.value.source_image_id license_type = each.value.license_type size = each.value.vm_type network_interface_ids = [ azurerm_network_interface.nic[each.key].id, ] identity { type = "SystemAssigned" } os_disk { name = "${each.value.vm_name}-${each.value.os_disk}" caching = "ReadWrite" storage_account_type = each.value.osdisk_type disk_size_gb = each.value.osdisk_size } computer_name = each.value.hostname admin_username = each.value.adminid admin_password = data.azurerm_key_vault_secret.password.value timezone = "Korea Standard Time" }
解决方案
错误原因
你的通用镜像包含数据磁盘,但当前Terraform代码仅定义了OS磁盘配置,未声明镜像中的数据磁盘信息。Azure API要求创建VM时必须匹配镜像中数据磁盘的LUN值,因此触发StorageProfile.dataDisks.lun缺失的参数错误。
修改后的代码(vm.tf)
通过添加data "azurerm_image"获取镜像元数据,再用dynamic "data_disk"块自动生成数据磁盘配置,确保与镜像的LUN值一致:
data "azurerm_resource_group" "system_rg_name" { name = var.system_rg } data "azurerm_subnet" "network_subnet" { name = var.network_subnet virtual_network_name = var.network_vnet resource_group_name = var.network_rg } # 加载镜像元数据,获取数据磁盘配置 data "azurerm_image" "vm_image" { for_each = var.vm_template # 从source_image_id拆分镜像名称和资源组 name = split("/", each.value.source_image_id)[length(split("/", each.value.source_image_id)) - 1] resource_group_name = split("/", each.value.source_image_id)[4] } resource "azurerm_network_interface" "nic" { for_each = var.vm_template name = "${each.value.vm_name}-${each.value.nic}" location = var.location resource_group_name = data.azurerm_resource_group.system_rg_name.name accelerated_networking_enabled = true ip_configuration { name = "internal" subnet_id = data.azurerm_subnet.network_subnet.id private_ip_address_allocation = var.private-ip-type private_ip_address = each.value.private_ip } } resource "azurerm_windows_virtual_machine" "vm" { for_each = var.vm_template name = each.value.vm_name location = var.location resource_group_name = data.azurerm_resource_group.system_rg_name.name source_image_id = each.value.source_image_id license_type = each.value.license_type size = each.value.vm_type network_interface_ids = [ azurerm_network_interface.nic[each.key].id, ] identity { type = "SystemAssigned" } os_disk { name = "${each.value.vm_name}-${each.value.os_disk}" caching = "ReadWrite" storage_account_type = each.value.osdisk_type disk_size_gb = each.value.osdisk_size } # 动态生成数据磁盘配置,匹配镜像中的LUN、大小、缓存策略 dynamic "data_disk" { for_each = data.azurerm_image.vm_image[each.key].storage_profile_data_disks content { lun = data_disk.value.lun caching = data_disk.value.caching disk_size_gb = data_disk.value.disk_size_gb storage_account_type = each.value.osdisk_type # 可替换为自定义存储类型 name = "${each.value.vm_name}-datadisk-${data_disk.value.lun}" } } computer_name = each.value.hostname admin_username = each.value.adminid admin_password = data.azurerm_key_vault_secret.password.value timezone = "Korea Standard Time" }
说明
data "azurerm_image":自动从source_image_id拆分镜像名称和所属资源组,加载镜像的完整配置,包括数据磁盘的LUN、大小、缓存方式等信息。dynamic "data_disk":遍历镜像中的所有数据磁盘,自动生成对应磁盘配置,确保每个数据磁盘的LUN值与镜像完全一致,满足Azure API参数要求。- 若需自定义数据磁盘存储类型,可将
storage_account_type替换为目标类型(如Premium_LRS),无需修改LUN值。
内容的提问来源于stack exchange,提问作者gotothesky
相关产品推荐
相关产品推荐

