2026-01-27 17:35:45 -05:00
---
name : azure-vms
description : Manage Azure Virtual Machines and scale sets. Configure availability sets and managed disks. Use when deploying compute resources on Azure.
license : MIT
metadata :
author : devops-skills
version : "1.0"
---
# Azure Virtual Machines
2026-03-24 18:02:50 -04:00
Deploy and manage Azure VMs, availability sets, scale sets, custom images, and managed disks. Covers VM creation, sizing, disk management, auto-scaling, and Terraform configurations for production environments.
2026-01-27 17:35:45 -05:00
2026-03-24 18:02:50 -04:00
## When to Use
- You need full control over the operating system and runtime environment.
- Your application requires specific OS configurations or kernel modules.
- You are running legacy applications that cannot be containerized.
- You need GPU-accelerated compute for ML training or rendering.
- You need high-availability compute with availability zones or scale sets.
## Prerequisites
```bash
# Install Azure CLI
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
# Login and set subscription
az login
az account set --subscription "my-subscription-id"
# Create resource group
az group create --name compute-rg --location eastus
# List available VM sizes in a region
az vm list-sizes --location eastus --output table
# List available VM images
az vm image list --output table
az vm image list --publisher Canonical --offer 0001-com-ubuntu-server-jammy --all --output table
```
## VM Creation
### Linux VM with SSH Key
2026-01-27 17:35:45 -05:00
```bash
az vm create \
2026-03-24 18:02:50 -04:00
--resource-group compute-rg \
--name myapp-vm \
--image Ubuntu2204 \
--size Standard_D4s_v5 \
--admin-username azureuser \
--generate-ssh-keys \
--vnet-name myapp-vnet \
--subnet app-subnet \
--nsg "" \
--public-ip-address "" \
--os-disk-size-gb 64 \
--os-disk-caching ReadWrite \
--storage-sku Premium_LRS \
--zone 1 \
--assign-identity \
--tags environment = prod team = platform app = myapp
# SSH into the VM (if public IP assigned)
ssh azureuser@$( az vm show -g compute-rg -n myapp-vm -d --query publicIps -o tsv)
```
### Windows VM
```bash
az vm create \
--resource-group compute-rg \
--name myapp-win-vm \
--image Win2022Datacenter \
--size Standard_D4s_v5 \
--admin-username azureadmin \
--admin-password 'S3cur3P@ssw0rd!' \
--vnet-name myapp-vnet \
--subnet app-subnet \
--public-ip-address "" \
--os-disk-size-gb 128 \
--storage-sku Premium_LRS \
--zone 1
```
### VM with Cloud-Init
```bash
# cloud-init.yaml
# #cloud-config
# package_update: true
# packages:
# - nginx
# - docker.io
# runcmd:
# - systemctl enable nginx
# - systemctl start nginx
# - usermod -aG docker azureuser
az vm create \
--resource-group compute-rg \
--name web-vm \
2026-01-27 17:35:45 -05:00
--image Ubuntu2204 \
--size Standard_B2s \
--admin-username azureuser \
--generate-ssh-keys \
2026-03-24 18:02:50 -04:00
--custom-data cloud-init.yaml \
--tags role = web
2026-01-27 17:35:45 -05:00
```
2026-03-24 18:02:50 -04:00
## VM Size Guide
| Family | Example Sizes | Use Case |
|--------|---------------|----------|
| B-series | Standard_B1s, Standard_B2s | Dev/test, low-traffic web servers |
| D-series | Standard_D4s_v5, Standard_D8s_v5 | General purpose, most production workloads |
| E-series | Standard_E4s_v5, Standard_E16s_v5 | Memory-intensive (databases, caching) |
| F-series | Standard_F4s_v2, Standard_F16s_v2 | CPU-intensive (batch processing, analytics) |
| L-series | Standard_L8s_v3, Standard_L32s_v3 | Storage-optimized (big data, SQL) |
| N-series | Standard_NC6s_v3, Standard_NC24ads_A100_v4 | GPU workloads (ML training, rendering) |
| M-series | Standard_M128s | SAP HANA, large in-memory workloads |
2026-01-27 17:35:45 -05:00
```bash
2026-03-24 18:02:50 -04:00
# Find VM sizes with specific capabilities
az vm list-sizes --location eastus \
--query "[?numberOfCores >= \`4\` && memoryInMb >= \`16000\`]" \
--output table
# Check VM size availability in a zone
az vm list-skus --location eastus \
--size Standard_D4s_v5 \
--output table
2026-01-27 17:35:45 -05:00
```
2026-03-24 18:02:50 -04:00
## Managed Disks
2026-01-27 17:35:45 -05:00
2026-03-24 18:02:50 -04:00
```bash
# Add a data disk to existing VM
az vm disk attach \
--resource-group compute-rg \
--vm-name myapp-vm \
--name myapp-data-disk \
--size-gb 256 \
--sku Premium_LRS \
--new \
--lun 0
# Create a standalone managed disk
az disk create \
--resource-group compute-rg \
--name shared-data-disk \
--size-gb 512 \
--sku Premium_LRS \
--zone 1
# Resize a disk (VM must be deallocated)
az vm deallocate --resource-group compute-rg --name myapp-vm
az disk update \
--resource-group compute-rg \
--name myapp-data-disk \
--size-gb 512
az vm start --resource-group compute-rg --name myapp-vm
# Snapshot a disk for backup
az snapshot create \
--resource-group compute-rg \
--name myapp-disk-snapshot \
--source myapp-data-disk
# Create disk from snapshot
az disk create \
--resource-group compute-rg \
--name myapp-disk-from-snap \
--source myapp-disk-snapshot \
--sku Premium_LRS
# List disks attached to a VM
az vm show \
--resource-group compute-rg \
--name myapp-vm \
--query "storageProfile.dataDisks" \
--output table
```
## Custom Images
```bash
# Generalize the VM (run inside the VM first)
# sudo waagent -deprovision+user -force
# Deallocate and generalize
az vm deallocate --resource-group compute-rg --name myapp-vm
az vm generalize --resource-group compute-rg --name myapp-vm
# Create image from VM
az image create \
--resource-group compute-rg \
--name myapp-golden-image \
--source myapp-vm \
--os-type Linux
# Create VM from custom image
az vm create \
--resource-group compute-rg \
--name myapp-from-image \
--image myapp-golden-image \
--size Standard_D4s_v5 \
--admin-username azureuser \
--generate-ssh-keys
# Use Azure Compute Gallery for shared images
az sig create \
--resource-group compute-rg \
--gallery-name myAppGallery
az sig image-definition create \
--resource-group compute-rg \
--gallery-name myAppGallery \
--gallery-image-definition myapp-image \
--publisher myorg \
--offer myapp \
--sku 1.0 \
--os-type Linux \
--os-state Generalized
az sig image-version create \
--resource-group compute-rg \
--gallery-name myAppGallery \
--gallery-image-definition myapp-image \
--gallery-image-version 1.0.0 \
--managed-image myapp-golden-image \
--target-regions eastus westus \
--replica-count 2
```
## Availability Sets and Zones
```bash
# Create availability set
az vm availability-set create \
--resource-group compute-rg \
--name myapp-avset \
--platform-fault-domain-count 3 \
--platform-update-domain-count 5
# Create VM in availability set
az vm create \
--resource-group compute-rg \
--name myapp-vm-1 \
--image Ubuntu2204 \
--size Standard_D4s_v5 \
--availability-set myapp-avset \
--admin-username azureuser \
--generate-ssh-keys
# Create VMs across availability zones
for zone in 1 2 3; do
az vm create \
--resource-group compute-rg \
--name "myapp-vm-zone ${ zone } " \
--image Ubuntu2204 \
--size Standard_D4s_v5 \
--zone " $zone " \
--admin-username azureuser \
--generate-ssh-keys \
--no-wait
done
```
## Virtual Machine Scale Sets
```bash
# Create VMSS with autoscaling
az vmss create \
--resource-group compute-rg \
--name myapp-vmss \
--image Ubuntu2204 \
--vm-sku Standard_D4s_v5 \
--instance-count 2 \
--admin-username azureuser \
--generate-ssh-keys \
--vnet-name myapp-vnet \
--subnet app-subnet \
--upgrade-policy-mode Rolling \
--health-probe "/" \
--load-balancer myapp-lb \
--zones 1 2 3 \
--custom-data cloud-init.yaml \
--tags environment = prod
# Configure autoscale rules
az monitor autoscale create \
--resource-group compute-rg \
--resource myapp-vmss \
--resource-type Microsoft.Compute/virtualMachineScaleSets \
--name myapp-autoscale \
--min-count 2 \
--max-count 20 \
--count 3
# Scale out when CPU > 70%
az monitor autoscale rule create \
--resource-group compute-rg \
--autoscale-name myapp-autoscale \
--condition "Percentage CPU > 70 avg 5m" \
--scale out 2
# Scale in when CPU < 30%
az monitor autoscale rule create \
--resource-group compute-rg \
--autoscale-name myapp-autoscale \
--condition "Percentage CPU < 30 avg 10m" \
--scale in 1
# Manual scale
az vmss scale \
--resource-group compute-rg \
--name myapp-vmss \
--new-capacity 5
# Update VMSS image
az vmss update \
--resource-group compute-rg \
--name myapp-vmss \
--set virtualMachineProfile.storageProfile.imageReference.version= latest
# Rolling upgrade of instances
az vmss rolling-upgrade start \
--resource-group compute-rg \
--name myapp-vmss
# List VMSS instances
az vmss list-instances \
--resource-group compute-rg \
--name myapp-vmss \
--output table
```
## VM Management Operations
```bash
# Start / Stop / Restart / Deallocate
az vm start --resource-group compute-rg --name myapp-vm
az vm stop --resource-group compute-rg --name myapp-vm
az vm restart --resource-group compute-rg --name myapp-vm
az vm deallocate --resource-group compute-rg --name myapp-vm
# Run command on a VM
az vm run-command invoke \
--resource-group compute-rg \
--name myapp-vm \
--command-id RunShellScript \
--scripts "df -h && free -m && uptime"
# Enable boot diagnostics
az vm boot-diagnostics enable \
--resource-group compute-rg \
--name myapp-vm
# Get boot diagnostics log
az vm boot-diagnostics get-boot-log \
--resource-group compute-rg \
--name myapp-vm
# Enable Azure Backup
az backup protection enable-for-vm \
--resource-group compute-rg \
--vault-name myapp-vault \
--vm myapp-vm \
--policy-name DefaultPolicy
# Resize a VM
az vm resize \
--resource-group compute-rg \
--name myapp-vm \
--size Standard_D8s_v5
```
## Terraform Configuration
```hcl
resource "azurerm_linux_virtual_machine" "main" {
name = "myapp-vm"
resource_group_name = azurerm_resource_group . main . name
location = azurerm_resource_group . main . location
size = "Standard_D4s_v5"
admin_username = "azureuser"
zone = "1"
network_interface_ids = [ azurerm_network_interface . main . id ]
admin_ssh_key {
username = "azureuser"
public_key = file ( "~/.ssh/id_rsa.pub" )
}
os_disk {
caching = "ReadWrite"
storage_account_type = "Premium_LRS"
disk_size_gb = 64
}
source_image_reference {
publisher = "Canonical"
offer = "0001-com-ubuntu-server-jammy"
sku = "22_04-lts-gen2"
version = "latest"
}
identity {
type = "SystemAssigned"
}
tags = var . tags
}
resource "azurerm_managed_disk" "data" {
name = "myapp-data-disk"
resource_group_name = azurerm_resource_group . main . name
location = azurerm_resource_group . main . location
storage_account_type = "Premium_LRS"
create_option = "Empty"
disk_size_gb = 256
zone = "1"
tags = var . tags
}
resource "azurerm_virtual_machine_data_disk_attachment" "data" {
managed_disk_id = azurerm_managed_disk . data . id
virtual_machine_id = azurerm_linux_virtual_machine . main . id
lun = 0
caching = "ReadOnly"
}
resource "azurerm_linux_virtual_machine_scale_set" "main" {
name = "myapp-vmss"
resource_group_name = azurerm_resource_group . main . name
location = azurerm_resource_group . main . location
sku = "Standard_D4s_v5"
instances = 3
admin_username = "azureuser"
zones = [ 1 , 2 , 3 ]
admin_ssh_key {
username = "azureuser"
public_key = file ( "~/.ssh/id_rsa.pub" )
}
source_image_reference {
publisher = "Canonical"
offer = "0001-com-ubuntu-server-jammy"
sku = "22_04-lts-gen2"
version = "latest"
}
os_disk {
caching = "ReadWrite"
storage_account_type = "Premium_LRS"
}
network_interface {
name = "vmss-nic"
primary = true
ip_configuration {
name = "internal"
primary = true
subnet_id = azurerm_subnet . app . id
}
}
automatic_os_upgrade_policy {
disable_automatic_rollback = false
enable_automatic_os_upgrade = true
}
rolling_upgrade_policy {
max_batch_instance_percent = 20
max_unhealthy_instance_percent = 20
max_unhealthy_upgraded_instance_percent = 5
pause_time_between_batches = "PT0S"
}
tags = var . tags
}
```
## Troubleshooting
| Symptom | Cause | Fix |
|---------|-------|-----|
| VM fails to start | Quota exceeded in region | Check quota with `az vm list-usage --location eastus` ; request increase |
| SSH connection refused | NSG blocking port 22 or VM not running | Check NSG rules and VM power state; use Azure Bastion for private VMs |
| VM disk full | OS disk too small or logs not rotated | Resize disk after deallocating; configure log rotation |
| VM performance is slow | Wrong VM size or disk throttling | Check metrics with `az monitor metrics list` ; upgrade size or disk tier |
| Scale set not scaling out | Autoscale rule threshold not met | Review autoscale settings; verify metric thresholds match workload |
| Custom image VM boot fails | Image not properly generalized | Re-run `waagent -deprovision` before capturing; check boot diagnostics |
| VMSS rolling upgrade stuck | Health probe failing on new instances | Fix application health endpoint; check `az vmss rolling-upgrade get-latest` |
| Spot VM evicted unexpectedly | Azure reclaimed capacity | Use eviction policy `Deallocate` and set up eviction notifications |
## Related Skills
- `azure-networking` -- VNet and NSG configuration for VM connectivity.
- `azure-aks` -- Container alternative when VMs are not required.
- `arm-templates` -- Bicep-based VM deployment templates.
- `terraform-azure` -- Terraform-based VM and VMSS provisioning.