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

能否通过Terraform将虚拟机现有OS磁盘替换为托管磁盘?

用Terraform实现Azure虚拟机OS磁盘替换的优化方案

问题场景

我已通过Terraform完成以下操作:

  1. 为当前虚拟机的OS磁盘创建快照
  2. 将快照转换为托管磁盘

但遇到问题:旧版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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 12:47:57