Sometimes you need to create a VM from disk snapshots - disaster recovery testing, creating dev environments from production snapshots, or migrating between subscriptions.
Here's how to do it properly with Terraform.
The Process
- Create managed disks from snapshots
- Create a NIC
- Create the VM using the managed disks
Creating Disks from Snapshots
# OS Disk from snapshot
resource "azurerm_managed_disk" "os_disk" {
name = "disk-vm-restored-os"
location = azurerm_resource_group.this.location
resource_group_name = azurerm_resource_group.this.name
storage_account_type = "Premium_LRS"
create_option = "Copy"
source_resource_id = data.azurerm_snapshot.os_snapshot.id
disk_size_gb = 128
tags = {
Environment = "dev"
Source = "snapshot-restore"
}
}
# Data Disk from snapshot
resource "azurerm_managed_disk" "data_disk" {
name = "disk-vm-restored-data"
location = azurerm_resource_group.this.location
resource_group_name = azurerm_resource_group.this.name
storage_account_type = "Premium_LRS"
create_option = "Copy"
source_resource_id = data.azurerm_snapshot.data_snapshot.id
disk_size_gb = 256
}
Referencing Existing Snapshots
data "azurerm_snapshot" "os_snapshot" {
name = "snap-prod-vm-os-20240801"
resource_group_name = "rg-snapshots"
}
data "azurerm_snapshot" "data_snapshot" {
name = "snap-prod-vm-data-20240801"
resource_group_name = "rg-snapshots"
}
Creating the VM
resource "azurerm_network_interface" "this" {
name = "nic-vm-restored"
location = azurerm_resource_group.this.location
resource_group_name = azurerm_resource_group.this.name
ip_configuration {
name = "internal"
subnet_id = azurerm_subnet.this.id
private_ip_address_allocation = "Dynamic"
}
}
resource "azurerm_linux_virtual_machine" "this" {
name = "vm-restored"
resource_group_name = azurerm_resource_group.this.name
location = azurerm_resource_group.this.location
size = "Standard_D4s_v3"
admin_username = "adminuser"
network_interface_ids = [
azurerm_network_interface.this.id
]
admin_ssh_key {
username = "adminuser"
public_key = file("~/.ssh/id_rsa.pub")
}
os_disk {
name = azurerm_managed_disk.os_disk.name
caching = "ReadWrite"
storage_account_type = "Premium_LRS"
}
source_image_id = null # Not needed when using existing disk
}
# Attach data disk
resource "azurerm_virtual_machine_data_disk_attachment" "data" {
managed_disk_id = azurerm_managed_disk.data_disk.id
virtual_machine_id = azurerm_linux_virtual_machine.this.id
lun = 0
caching = "ReadOnly"
}
Important Notes
OS Disk attachment - When creating a VM from an existing OS disk, you can't use source_image_reference. The disk already has the OS.
Disk size - The new disk must be at least as large as the snapshot source.
Storage account type - Can be different from the source. Useful for creating Standard disks from Premium snapshots in dev environments.
Cross-region - Snapshots are regional. To restore in a different region, first copy the snapshot.
Windows VMs
For Windows, use azurerm_windows_virtual_machine:
resource "azurerm_windows_virtual_machine" "this" {
name = "vm-restored-win"
resource_group_name = azurerm_resource_group.this.name
location = azurerm_resource_group.this.location
size = "Standard_D4s_v3"
admin_username = "adminuser"
admin_password = var.admin_password
network_interface_ids = [
azurerm_network_interface.this.id
]
os_disk {
name = azurerm_managed_disk.os_disk.name
caching = "ReadWrite"
storage_account_type = "Premium_LRS"
}
}
Automating Snapshot Creation
For regular snapshots, use Azure Backup or a scheduled pipeline:
resource "azurerm_snapshot" "os_disk" {
name = "snap-vm-os-${formatdate("YYYYMMDD", timestamp())}"
location = azurerm_resource_group.this.location
resource_group_name = azurerm_resource_group.this.name
create_option = "Copy"
source_uri = azurerm_managed_disk.source_os.id
}
Need help with backup and disaster recovery in Azure? Get in touch - we help organisations protect their cloud infrastructure.