EthicsComputerCourses
Join training +91 90532 10052

Virtual Machines & Scale Sets

Microsoft Azure · Lesson 13 of 29 Intermediate 7 min read Updated

By the end of this lesson you will be able to choose a VM size and image, create a Linux VM that installs a web server on first boot, run a command on it without SSH, stop it so billing for compute stops, and run a group of identical VMs with a scale set that grows and shrinks with load.

What is an Azure virtual machine?

An Azure virtual machine (VM) is a computer that runs in Microsoft's data centre. It has CPUs, memory, disks and a network card, and you install and manage its operating system. This is IaaS: maximum control, maximum responsibility. You patch it, secure it and back it up.

A VM is like renting a furnished flat. The building, water and electricity are the landlord's job. Locking the door, cleaning and what you put inside are yours.

Use VMs when you need full control: custom software, older apps that expect a full server, special drivers, or lift-and-shift migration from an office data centre. For a normal web app, App Service is usually less work.

Sizes, images and disks

Sizes describe CPU, memory and features. Read a size name from left to right:

Part of Standard_D2s_v5Meaning
DFamily: general purpose. Others: B burstable, E memory-heavy, F compute-heavy, N GPU
2Number of vCPUs (virtual CPUs)
sSupports Premium SSD disks
v5Generation of the hardware

B-series (burstable) VMs earn CPU credits while idle and spend them in short bursts. They suit small websites and practice labs.

Images are templates for the operating system disk, such as Ubuntu Server 24.04 LTS or Windows Server. They come from the Azure Marketplace and are named by a URN, publisher:offer:sku:version. The CLI also accepts short aliases such as Ubuntu2404; run az vm image list --output table to see the aliases your CLI version knows.

Managed disks store data. Every VM has an OS disk and can have data disks. Disk types range from Standard HDD (cheapest, slowest) through Standard SSD and Premium SSD to Premium SSD v2 and Ultra Disk (fastest). Many sizes also have a temporary disk that is wiped when the VM moves hosts: never keep important files there.

Step by step: a web server VM with cloud-init

cloud-init is a standard tool that runs setup instructions on a Linux VM's first boot. You pass it as custom data.

Step 1: save this file as cloud-init.yaml. It installs nginx and writes a home page.

YAML
#cloud-config
package_update: true
packages:
  - nginx
write_files:
  - path: /var/www/html/index.html
    content: |
      <h1>Rohtak Library Catalogue</h1>
      <p>Served from an Azure VM.</p>
runcmd:
  - systemctl enable --now nginx

Step 2: create the resource group and the VM. This VM gets a public IP so you can test it; production VMs usually sit behind a load balancer with no public IP.

Terminal
az group create --name rg-vm-demo --location centralindia --output none

az vm create --resource-group rg-vm-demo --name vm-library-01 \
  --image Ubuntu2404 --size Standard_B2s \
  --admin-username azureuser --generate-ssh-keys \
  --custom-data cloud-init.yaml --public-ip-sku Standard
Output
{
  "fqdns": "",
  "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-vm-demo/providers/Microsoft.Compute/virtualMachines/vm-library-01",
  "location": "centralindia",
  "macAddress": "00-0D-3A-00-00-01",
  "powerState": "VM running",
  "privateIpAddress": "10.0.0.4",
  "publicIpAddress": "203.0.113.40",
  "resourceGroup": "rg-vm-demo",
  "zones": ""
}

This output is traced from Microsoft's VM quickstart with placeholder addresses. --generate-ssh-keys uses your existing SSH key or creates one in ~/.ssh. The command also creates a VNet, subnet, NSG, public IP and NIC for you, all named after the VM.

Step 3: open port 80 in the VM's NSG and visit http://<publicIpAddress>.

Terminal
az vm open-port --resource-group rg-vm-demo --name vm-library-01 --port 80 --priority 900 --output none

You should see "Rohtak Library Catalogue" in the browser.

Step 4: run a command inside the VM without SSH, using Run Command:

Terminal
az vm run-command invoke --resource-group rg-vm-demo --name vm-library-01 \
  --command-id RunShellScript --scripts "systemctl is-active nginx" \
  --query "value[0].message" --output tsv
Output
Enable succeeded: 
[stdout]
active

[stderr]

The message format is traced from the Run Command documentation.

Stopped versus deallocated

This difference costs learners real money:

StateHow you get thereCompute billing
RunningNormalYes
StoppedShutting down from inside the OS, or az vm stopYes, the hardware is still reserved
Stopped (deallocated)az vm deallocate, or Stop in the portalNo, but disks are still billed
Terminal
az vm deallocate --resource-group rg-vm-demo --name vm-library-01
az vm get-instance-view --resource-group rg-vm-demo --name vm-library-01 \
  --query "instanceView.statuses[1].displayStatus" --output tsv
Output
VM deallocated

You can also set auto-shutdown in the portal so practice VMs deallocate every evening.

Availability: sets, zones and scale sets

A single VM can fail during hardware faults or maintenance. Options, from oldest to newest:

  • Availability sets spread VMs across fault domains (separate racks) and update domains in one data centre. You still meet them in older designs.
  • Availability zones place VMs in different buildings of a region, as you saw in Regions.
  • Virtual Machine Scale Sets manage a group of VMs as one, spread them across zones and add or remove instances automatically.

Scale sets

A scale set is like a bus depot that adds buses on festival days and parks them afterwards. Use Flexible orchestration, the recommended mode for new scale sets. Uniform mode is the older style where every instance is identical and managed only through the scale set.

Step 1: create a zone-spread Flexible scale set with the same cloud-init file.

Terminal
az vmss create --resource-group rg-vm-demo --name vmss-library \
  --orchestration-mode Flexible --image Ubuntu2404 --vm-sku Standard_B2s \
  --instance-count 2 --zones 1 2 3 \
  --admin-username azureuser --generate-ssh-keys --custom-data cloud-init.yaml --output none

Step 2: add autoscale rules: keep 2 to 6 instances, add one when average CPU stays above 70% for 5 minutes, remove one below 30%.

Terminal
az monitor autoscale create --resource-group rg-vm-demo --name as-library \
  --resource vmss-library --resource-type Microsoft.Compute/virtualMachineScaleSets \
  --min-count 2 --max-count 6 --count 2 --output none

az monitor autoscale rule create --resource-group rg-vm-demo --autoscale-name as-library \
  --condition "Percentage CPU > 70 avg 5m" --scale out 1 --output none
az monitor autoscale rule create --resource-group rg-vm-demo --autoscale-name as-library \
  --condition "Percentage CPU < 30 avg 5m" --scale in 1 --output none

Put the scale set behind a load balancer so users always reach a healthy instance.

Clean up: az group delete --name rg-vm-demo --yes --no-wait.

Common mistakes

  • Shutting down from inside Linux and assuming billing stops. Deallocate instead.
  • Leaving port 22 open to the internet. Use Azure Bastion or Run Command.
  • Storing data on the temporary disk. It can be wiped. Use a managed data disk.
  • Building pets. Hand-configured servers are hard to replace. Use cloud-init and scale sets so any instance can be rebuilt.

Key points

  • A VM is IaaS: you manage the OS, patches and security.
  • Size names encode family, vCPUs, features and generation; B-series suits small workloads.
  • cloud-init custom data configures Linux VMs on first boot; Run Command runs scripts without SSH.
  • Only a deallocated VM stops compute billing; disks are billed until deleted.
  • Flexible scale sets with autoscale and zones give resilient, elastic VM groups.

Exercise

Write the commands to create a VM named vm-exam-01 in rg-exam (Central India) using the Ubuntu2404 image, size Standard_B1s, SSH keys, no public IP (--public-ip-address ""), and then deallocate it. Explain in one sentence why a VM without a public IP is safer.

Show solution
Terminal
az group create --name rg-exam --location centralindia --output none
az vm create --resource-group rg-exam --name vm-exam-01 --image Ubuntu2404 --size Standard_B1s \
  --admin-username azureuser --generate-ssh-keys --public-ip-address "" --output none
az vm deallocate --resource-group rg-exam --name vm-exam-01

Without a public IP, nothing on the internet can even try to connect to the VM; you reach it through Bastion or Run Command, and it reaches the internet only through an explicit outbound method such as a NAT gateway.

Quick Quiz

1. Which state stops compute billing for a VM?

2. What does the s in Standard_D2s_v5 mean?

3. Which orchestration mode is recommended for new scale sets?

Learn Microsoft Azure with a mentor

Free lessons get you started. Our Cloud & DevOps training adds real projects and code reviews from working developers.

  • Project-based learning
  • Mentor code reviews
  • Free counselling call