能否通过Terraform将虚拟机现有OS磁盘替换为托管磁盘?
用Terraform实现Azure虚拟机OS磁盘替换的优化方案
问题场景
我已通过Terraform完成以下操作:
- 为当前虚拟机的OS磁盘创建快照
- 将快照转换为托管磁盘
但遇到问题:旧版azurerm_virtual_machine资源支持直接替换OS磁盘,现在该功能已被移除。虽然Azure门户支持OS磁盘交换操作,但我不确定如何用Terraform实现。
我自己通过null_resource调用Azure CLI实现了功能,想知道是否有更优的方案。
初始实现代码(snap.tf)
# OS DISK -> snapshot resource "azurerm_snapshot" "tf" { name = "snapshotpspl" location = var.location resource_group_name = data.azurerm_resource_group.system_rg_name.name create_option = "Copy" source_uri = "/subscriptions/.../osdisk01" } # snapshot -> managed disk resource "azurerm_managed_disk" "copy" { name = "managed1" location = var.location resource_group_name = data.azurerm_resource_group.system_rg_name.name storage_account_type = "StandardSSD_LRS" create_option = "Copy" source_resource_id = "/subscriptions/.../snapshotpspl" disk_size_gb = "256" }
当前运行正常的实现代码
disk_snap.tf
variable "vm_snap" { type = map(any) default = { snap1 = { snap_name = "osdisk01_snap01" snap_option = "Copy" # [1]disk source id snap_source_id = "/subscriptions/.../osdisk01" managed_disk_name = "osdisk01-new01" managed_disk_type = "StandardSSD_LRS" managed_option = "Copy" # [2]Managed source id managed_source_id = "/subscriptions/.../osdisk01_snap01" managed_size = "512" managed_v_ge = "V2" managed_os_type = "Linux" } } } ## [1] DISK -> Snapshot resource "azurerm_snapshot" "tf" { for_each = var.vm_snap name = each.value.snap_name location = var.location resource_group_name = var.rg create_option = each.value.snap_option source_uri = each.value.snap_source_id } ## [2] Snapshot -> managed disk resource "azurerm_managed_disk" "copy" { for_each = var.vm_snap name = each.value.managed_disk_name location = var.location resource_group_name = var.rg storage_account_type = each.value.managed_disk_type create_option = each.value.managed_option source_resource_id = each.value.managed_source_id disk_size_gb = each.value.managed_size hyper_v_generation = each.value.managed_v_ge os_type = each.value.managed_os_type depends_on = [azurerm_snapshot.tf] }
os_disk_swap.tf
## swap osdisk -> manageddisk resource "null_resource" "osdisk_swap" { provisioner "local-exec" { command = "az vm update --name vm-teset --resource-group tg-test --os-disk /subscriptions/.../osdisk01-new01" } }
更优实现方案
方案1:优化null_resource实现(适合低停机场景)
当前的null_resource存在硬编码ID的问题,可通过Terraform资源引用替代硬编码,同时添加触发器保证幂等性:
resource "null_resource" "osdisk_swap" { # 当托管磁盘ID变化时,重新执行交换操作 triggers = { managed_disk_id = azurerm_managed_disk.copy["snap1"].id vm_name = var.vm_name rg_name = var.rg } provisioner "local-exec" { command = "az vm update --name ${var.vm_name} --resource-group ${var.rg} --os-disk ${azurerm_managed_disk.copy["snap1"].id}" } # 确保托管磁盘创建完成后再执行交换 depends_on = [azurerm_managed_disk.copy] }
这种方式保留了Azure CLI交换OS磁盘的特性(需先停止VM,交换后启动),同时符合Terraform的配置一致性要求,避免硬编码带来的维护问题。
方案2:声明式修改VM的OS磁盘(适合可停机重建场景)
如果业务允许虚拟机停机重建,可直接修改azurerm_virtual_machine资源的os_disk块,引用新创建的托管磁盘:
resource "azurerm_virtual_machine" "example" { # 保留原有VM的其他配置(如名称、资源组、网络配置等) os_disk { name = azurerm_managed_disk.copy["snap1"].name managed_disk_id = azurerm_managed_disk.copy["snap1"].id storage_account_type = azurerm_managed_disk.copy["snap1"].storage_account_type caching = "ReadWrite" } # 其他配置... }
这种方式完全采用Terraform的声明式管理,不需要依赖外部CLI,配置更简洁,适合可以接受VM重建的场景。
内容的提问来源于stack exchange,提问作者gotothesky
相关产品推荐
相关产品推荐

