Azure Virtual Machines — Launch, Connect, and Manage Your First VM
Your team needs a Linux server running in the cloud by end of day. You could click through the Azure portal for 15 minutes, or you could type one CLI command and have a production-ready VM in under 3 minutes. Let us go with option two.
Choosing the Right VM Size
Azure offers over 700 VM sizes across multiple families. Picking the wrong one means either wasting money or hitting performance walls. Here is a cheat sheet for the most common families:
| Series | Optimized For | vCPUs | RAM | Use Case |
|---|---|---|---|---|
| B | Burstable | 1-20 | 0.5-80 GB | Dev/test, low-traffic web servers |
| D | General Purpose | 2-96 | 8-384 GB | Most production workloads |
| E | Memory Optimized | 2-104 | 16-672 GB | Databases, in-memory caching |
| F | Compute Optimized | 2-72 | 4-144 GB | Batch processing, gaming servers |
| N | GPU | 6-24 | 112-448 GB | ML training, video rendering |
Pro tip: Start with a B-series for development and testing. A Standard_B2s (2 vCPUs, 4 GB RAM) costs roughly $30/month and handles most non-production workloads.
Creating Your First VM
# Create a resource group first
az group create --name rg-dev-compute-eastus --location eastus
# Create an Ubuntu VM with SSH key authentication
az vm create \
--resource-group rg-dev-compute-eastus \
--name vm-dev-web-001 \
--image Ubuntu2204 \
--size Standard_B2s \
--admin-username azureuser \
--generate-ssh-keys \
--public-ip-sku Standard \
--tags Environment=Development Team=Platform
This single command creates the VM plus a virtual network, subnet, public IP, network security group, and network interface. Azure wires them all together automatically.
Listing Available VM Sizes for Your Region
# List VM sizes available in East US
az vm list-sizes \
--location eastus \
--output table \
--query "[?starts_with(name, 'Standard_B')]"
Connecting to Your VM
SSH (Linux VMs)
# Get the public IP
az vm show \
--resource-group rg-dev-compute-eastus \
--name vm-dev-web-001 \
--show-details \
--query publicIps \
--output tsv
# Connect via SSH
ssh azureuser@<public-ip>
RDP (Windows VMs)
For Windows VMs, you need to open port 3389:
# Create a Windows VM
az vm create \
--resource-group rg-dev-compute-eastus \
--name vm-dev-win-001 \
--image Win2022Datacenter \
--size Standard_B2s \
--admin-username azureuser \
--admin-password 'YourP@ssw0rd123!' \
--public-ip-sku Standard
# Open RDP port
az vm open-port \
--resource-group rg-dev-compute-eastus \
--name vm-dev-win-001 \
--port 3389
Managed Disks
Every VM needs at least an OS disk. Azure Managed Disks handle the storage account complexity for you. Here are your options:
| Disk Type | IOPS (max) | Throughput | Cost (128 GB/mo) | Use Case |
|---|---|---|---|---|
| Standard HDD | 500 | 60 MB/s | ~$5 | Backups, dev/test |
| Standard SSD | 6,000 | 750 MB/s | ~$10 | Web servers, light workloads |
| Premium SSD | 7,500 | 250 MB/s | ~$19 | Production databases |
| Ultra Disk | 160,000 | 4,000 MB/s | ~$65+ | SAP HANA, top-tier databases |
Adding a Data Disk
# Attach a 128 GB Premium SSD data disk
az vm disk attach \
--resource-group rg-dev-compute-eastus \
--vm-name vm-dev-web-001 \
--name disk-data-web-001 \
--size-gb 128 \
--sku Premium_LRS \
--new
After attaching, SSH into the VM and format the disk:
# Inside the VM — find the new disk
lsblk
# Partition, format, and mount
sudo parted /dev/sdc --script mklabel gpt mkpart primary ext4 0% 100%
sudo mkfs.ext4 /dev/sdc1
sudo mkdir /data
sudo mount /dev/sdc1 /data
# Persist the mount across reboots
echo '/dev/sdc1 /data ext4 defaults 0 2' | sudo tee -a /etc/fstab
Availability: Sets vs Zones
Downtime is not an option for production. Azure gives you two strategies:
Availability Sets distribute VMs across fault domains (separate racks) and update domains (separate maintenance windows) within a single datacenter. You get 99.95% SLA.
Availability Zones spread VMs across physically separate datacenters in a region. You get 99.99% SLA.
# Create a VM in a specific availability zone
az vm create \
--resource-group rg-dev-compute-eastus \
--name vm-prod-web-001 \
--image Ubuntu2204 \
--size Standard_D2s_v5 \
--zone 1 \
--admin-username azureuser \
--generate-ssh-keys
Use Availability Zones for production workloads whenever the region supports them. Use Availability Sets only when zones are unavailable.
VM Scale Sets
Need to auto-scale from 2 to 50 instances based on CPU load? VM Scale Sets handle this automatically.
# Create a scale set with 2 initial instances
az vmss create \
--resource-group rg-dev-compute-eastus \
--name vmss-web \
--image Ubuntu2204 \
--vm-sku Standard_B2s \
--instance-count 2 \
--admin-username azureuser \
--generate-ssh-keys \
--upgrade-policy-mode automatic
# Add auto-scale rule: scale out when CPU > 70%
az monitor autoscale create \
--resource-group rg-dev-compute-eastus \
--resource vmss-web \
--resource-type Microsoft.Compute/virtualMachineScaleSets \
--min-count 2 \
--max-count 10 \
--count 2
az monitor autoscale rule create \
--resource-group rg-dev-compute-eastus \
--autoscale-name vmss-web \
--condition "Percentage CPU > 70 avg 5m" \
--scale out 2
Cloud-Init: Configure VMs at Boot
Cloud-init lets you install packages, write files, and run commands the instant a VM boots — no SSH required.
Create a file called cloud-init.yaml:
#cloud-config
package_update: true
packages:
- nginx
- docker.io
- curl
runcmd:
- systemctl enable nginx
- systemctl start nginx
- echo "<h1>Hello from $(hostname)</h1>" > /var/www/html/index.html
Then pass it when creating the VM:
az vm create \
--resource-group rg-dev-compute-eastus \
--name vm-dev-web-002 \
--image Ubuntu2204 \
--size Standard_B2s \
--admin-username azureuser \
--generate-ssh-keys \
--custom-data cloud-init.yaml
Within 60 seconds of boot, your VM has Nginx and Docker running with a custom landing page.
Cost Optimization: Pay-as-you-go vs Reserved vs Spot
| Pricing Model | Discount | Commitment | Best For |
|---|---|---|---|
| Pay-as-you-go | 0% | None | Dev/test, variable workloads |
| 1-Year Reserved | ~35% | 1 year | Steady-state production |
| 3-Year Reserved | ~55% | 3 years | Long-running infrastructure |
| Spot Instances | Up to 90% | None (can be evicted) | Batch jobs, fault-tolerant work |
Managing VM Power State
Stop billing when you are not using a VM:
# Deallocate (stops billing for compute, keeps disk)
az vm deallocate \
--resource-group rg-dev-compute-eastus \
--name vm-dev-web-001
# Start it back up
az vm start \
--resource-group rg-dev-compute-eastus \
--name vm-dev-web-001
# Check power state
az vm get-instance-view \
--resource-group rg-dev-compute-eastus \
--name vm-dev-web-001 \
--query instanceView.statuses[1].displayStatus \
--output tsv
Important: az vm stop keeps the VM allocated and you still pay for compute. Always use az vm deallocate to stop billing.
Wrapping Up
Azure VMs are the workhorse of cloud computing. Pick the right size family, use managed disks, deploy across availability zones, and automate configuration with cloud-init. Most importantly, deallocate your dev VMs at night — your finance team will thank you.
Next up: We dive into Azure Storage — Blobs, Queues, Tables, and Files — the four pillars of cloud-native data storage.
