Azure Compute Skills
Virtual Machines
Creating VMs
# Linux VM with SSH key
az vm create \
--resource-group myRG \
--name myLinuxVM \
--image Ubuntu2204 \
--size Standard_B2s \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_rsa.pub \
--vnet-name myVNet \
--subnet WebSubnet \
--public-ip-sku Standard \
--no-wait
# Windows VM with password
az vm create \
--resource-group myRG \
--name myWinVM \
--image Win2022Datacenter \
--size Standard_D4s_v5 \
--admin-username adminuser \
--admin-password "P@ssw0rd123!" \
--no-public-ip-address # no public IP — access via Bastion
# Spot VM (significantly cheaper, can be evicted)
az vm create \
--resource-group myRG \
--name mySpotVM \
--image Ubuntu2204 \
--size Standard_D4s_v5 \
--priority Spot \
--eviction-policy Deallocate \
--max-price -1 # -1 = pay up to on-demand price
VM Common Operations
# Start / stop / restart / deallocate
az vm start -g myRG -n myVM
az vm stop -g myRG -n myVM # stops OS but still bills for compute
az vm deallocate -g myRG -n myVM # stops billing for compute
az vm restart -g myRG -n myVM
# Power state
az vm get-instance-view -g myRG -n myVM \
--query "instanceView.statuses[1].displayStatus" -o tsv
# Resize a VM
az vm resize -g myRG -n myVM --size Standard_D8s_v5
# List available sizes in a region
az vm list-sizes --location eastus --output table | grep Standard_D
# Run a command on a VM (via VM agent — no SSH needed)
az vm run-command invoke \
-g myRG -n myVM \
--command-id RunShellScript \
--scripts "apt-get update && apt-get install -y nginx"
# Create a snapshot of OS disk
DISK_ID=$(az vm show -g myRG -n myVM --query "storageProfile.osDisk.managedDisk.id" -o tsv)
az snapshot create -g myRG -n mySnapshot --source "$DISK_ID"
# Open a port (creates NSG rule)
az vm open-port -g myRG -n myVM --port 443 --priority 900
VM Availability
# Create Availability Set (max 2 fault domains for most regions)
az vm availability-set create \
--name myAvSet \
--resource-group myRG \
--platform-fault-domain-count 2 \
--platform-update-domain-count 5
az vm create -g myRG -n myVM1 --availability-set myAvSet ...
az vm create -g myRG -n myVM2 --availability-set myAvSet ...
# Availability Zones (preferred — uses separate physical infrastructure)
az vm create -g myRG -n myVM-zone1 --zone 1 ...
az vm create -g myRG -n myVM-zone2 --zone 2 ...
az vm create -g myRG -n myVM-zone3 --zone 3 ...
# Check zone support for a VM size
az vm list-skus \
--location eastus \
--size Standard_D4s_v5 \
--query "[].{Name:name, Zones:locationInfo[0].zones}" \
--output table
VM Size Families (Quick Reference)
B-series → Burstable; cheap for dev/test (Standard_B2s, B4ms)
D-series → General purpose; balanced CPU/memory (Standard_D4s_v5)
E-series → Memory-optimized; databases, caches (Standard_E8s_v5)
F-series → Compute-optimized; CPU-heavy workloads (Standard_F8s_v2)
L-series → Storage-optimized; NVMe local SSDs (Standard_L8s_v3)
M-series → Massive memory; up to 11.4 TB RAM (Standard_M128ms)
N-series → GPU; AI/ML training (Standard_NC6s_v3, NV-series for viz)
HB/HC → HPC; InfiniBand interconnect
Virtual Machine Scale Sets (VMSS)
# Create VMSS with autoscale
az vmss create \
--resource-group myRG \
--name myVMSS \
--image Ubuntu2204 \
--vm-sku Standard_D2s_v5 \
--instance-count 2 \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_rsa.pub \
--vnet-name myVNet \
--subnet AppSubnet \
--upgrade-policy-mode Automatic \
--load-balancer myLB \
--backend-pool-name BackendPool
# Configure autoscale
az monitor autoscale create \
--resource-group myRG \
--resource myVMSS \
--resource-type Microsoft.Compute/virtualMachineScaleSets \
--name myAutoscale \
--min-count 2 \
--max-count 10 \
--count 2
# Add scale-out rule (CPU > 70% for 5 min → add 2 instances)
az monitor autoscale rule create \
--resource-group myRG \
--autoscale-name myAutoscale \
--condition "Percentage CPU > 70 avg 5m" \
--scale out 2
# Add scale-in rule
az monitor autoscale rule create \
--resource-group myRG \
--autoscale-name myAutoscale \
--condition "Percentage CPU < 30 avg 10m" \
--scale in 1
# Manually scale
az vmss scale --resource-group myRG --name myVMSS --new-capacity 5
# Rolling upgrade
az vmss update-instances --resource-group myRG --name myVMSS --instance-ids '*'
App Service
# Create App Service Plan
az appservice plan create \
--name myPlan \
--resource-group myRG \
--sku P1v3 \
--is-linux
# Create Web App
az webapp create \
--resource-group myRG \
--plan myPlan \
--name myapp-uniquename \
--runtime "NODE:20-lts"
# Deploy from GitHub (CI/CD)
az webapp deployment source config \
--name myapp-uniquename \
--resource-group myRG \
--repo-url https://github.com/myorg/myrepo \
--branch main \
--manual-integration
# Deploy from local ZIP
az webapp deploy \
--resource-group myRG \
--name myapp-uniquename \
--src-path ./build.zip \
--type zip
# Configure app settings
az webapp config appsettings set \
--resource-group myRG \
--name myapp-uniquename \
--settings NODE_ENV=production DB_HOST=mydb.database.windows.net
# Stream logs
az webapp log tail --resource-group myRG --name myapp-uniquename
# Create deployment slot
az webapp deployment slot create \
--resource-group myRG \
--name myapp-uniquename \
--slot staging
# Swap slots (blue-green deployment)
az webapp deployment slot swap \
--resource-group myRG \
--name myapp-uniquename \
--slot staging \
--target-slot production
# Scale out (App Service Plan)
az appservice plan update \
--name myPlan \
--resource-group myRG \
--number-of-workers 3
App Service SKUs
F1 / D1 → Free / Shared (no SLA, no custom domain)
B1/B2/B3 → Basic — no autoscale, no slots; dev/test
S1/S2/S3 → Standard — autoscale, 5 slots, custom domains + SSL
P1v3/P2v3/P3v3 → Premium v3 — faster compute, VNET integration, 20 slots
P0v3 → Budget Premium — cheapest VNet integration option
EP1/EP2/EP3 → Elastic Premium (for Functions)
I1v2/I2v2 → Isolated v2 (App Service Environment — single tenant)
Azure Container Apps
# Create Container Apps environment (with VNet injection)
az containerapp env create \
--name myEnv \
--resource-group myRG \
--location eastus \
--infrastructure-subnet-resource-id /subscriptions/<sub>/resourceGroups/myRG/providers/Microsoft.Network/virtualNetworks/myVNet/subnets/ContainerAppsSubnet
# Deploy a container app
az containerapp create \
--name myapp \
--resource-group myRG \
--environment myEnv \
--image mcr.microsoft.com/azuredocs/containerapps-helloworld:latest \
--target-port 80 \
--ingress external \
--min-replicas 1 \
--max-replicas 10 \
--cpu 0.5 \
--memory 1.0Gi
# Scale rules — HTTP-based autoscale
az containerapp update \
--name myapp \
--resource-group myRG \
--scale-rule-name http-scale \
--scale-rule-type http \
--scale-rule-http-concurrency 50
# Update container image (triggers rolling deployment)
az containerapp update \
--name myapp \
--resource-group myRG \
--image myregistry.azurecr.io/myapp:v2.0
# Stream logs
az containerapp logs show \
--name myapp \
--resource-group myRG \
--follow
# Create a job (one-shot or scheduled)
az containerapp job create \
--name myjob \
--resource-group myRG \
--environment myEnv \
--trigger-type Schedule \
--cron-expression "0 6 * * *" \
--image myregistry.azurecr.io/myjob:latest \
--cpu 1 \
--memory 2Gi
Azure Functions
# Create Function App — Consumption plan (Linux)
az functionapp create \
--resource-group myRG \
--consumption-plan-location eastus \
--runtime python \
--runtime-version 3.11 \
--functions-version 4 \
--name myfuncapp-unique \
--storage-account mystorageacct \
--os-type linux
# Create Function App — Elastic Premium (VNet, no cold start)
az functionapp create \
--resource-group myRG \
--plan myPremiumPlan \
--runtime python \
--runtime-version 3.11 \
--functions-version 4 \
--name myfuncapp-premium \
--storage-account mystorageacct
# Deploy via ZIP
az functionapp deployment source config-zip \
--resource-group myRG \
--name myfuncapp-unique \
--src ./function.zip
# Configure settings
az functionapp config appsettings set \
--name myfuncapp-unique \
--resource-group myRG \
--settings AzureWebJobsStorage="<conn-string>" FUNCTIONS_WORKER_RUNTIME=python
# List functions
az functionapp function list \
--name myfuncapp-unique \
--resource-group myRG \
--output table
Function Plans Comparison
Consumption → Pay per execution; cold starts; max 10min timeout; no VNet (without Premium)
Flex → New in 2024; faster scale, VNet support, per-execution billing
Elastic Prem → Always warm; VNet; max 60min; higher base cost
Dedicated → App Service Plan; predictable cost; max timeout unlimited
Container Apps → Full container control; KEDA-based scaling
AKS (Azure Kubernetes Service)
# Create AKS cluster
az aks create \
--resource-group myRG \
--name myAKS \
--node-count 3 \
--node-vm-size Standard_D4s_v5 \
--enable-managed-identity \
--enable-oidc-issuer \
--enable-workload-identity \
--network-plugin azure \
--network-policy azure \
--vnet-subnet-id /subscriptions/<sub>/resourceGroups/myRG/providers/Microsoft.Network/virtualNetworks/myVNet/subnets/AKSSubnet \
--enable-cluster-autoscaler \
--min-count 3 \
--max-count 10 \
--zones 1 2 3 \
--kubernetes-version 1.29 \
--tier standard \
--generate-ssh-keys
# Get credentials
az aks get-credentials --resource-group myRG --name myAKS --overwrite-existing
# Add a node pool (e.g., GPU or spot nodes)
az aks nodepool add \
--resource-group myRG \
--cluster-name myAKS \
--name gpupool \
--node-vm-size Standard_NC6s_v3 \
--node-count 1 \
--node-taints sku=gpu:NoSchedule \
--labels accelerator=nvidia
# Add a spot node pool
az aks nodepool add \
--resource-group myRG \
--cluster-name myAKS \
--name spotnodes \
--priority Spot \
--eviction-policy Delete \
--spot-max-price -1 \
--enable-cluster-autoscaler \
--min-count 0 \
--max-count 20 \
--node-taints kubernetes.azure.com/scalesetpriority=spot:NoSchedule
# Upgrade cluster
# Always check available versions first — AKS supports roughly the latest 3
# minor versions (N, N-1, N-2) and rolls forward continuously; don't hard-code.
az aks get-upgrades --resource-group myRG --name myAKS --output table
# List versions available in the region:
az aks get-versions --location eastus --output table
# Then upgrade to a currently-supported version (substitute the value you saw above):
az aks upgrade --resource-group myRG --name myAKS --kubernetes-version <supported-version>
# Enable addons
az aks enable-addons \
--resource-group myRG \
--name myAKS \
--addons monitoring \
--workspace-resource-id /subscriptions/<sub>/resourceGroups/myRG/providers/Microsoft.OperationalInsights/workspaces/myLAW
# AKS RBAC — assign cluster role to a user
az role assignment create \
--assignee user@example.com \
--role "Azure Kubernetes Service Cluster User Role" \
--scope /subscriptions/<sub>/resourceGroups/myRG/providers/Microsoft.ContainerService/managedClusters/myAKS
AKS Networking Modes
Kubenet → Simple overlay; nodes get VNet IPs, pods get NAT'd RFC1918 IPs (limited scale)
Azure CNI → Pods get VNet IPs; requires more IP space; full VNet visibility
Azure CNI Overlay → Pods get private overlay IPs; nodes in VNet; best of both (recommended 2024+)
Azure CNI Dynamic IP → Efficient IP allocation for Azure CNI
Azure Container Instances (ACI)
# Quick single container deployment (no orchestration overhead)
az container create \
--resource-group myRG \
--name mycontainer \
--image nginx:alpine \
--cpu 1 \
--memory 1.5 \
--ports 80 \
--ip-address Public \
--dns-name-label mycontainer-uniquelabel
# Container with environment variables and secrets
az container create \
--resource-group myRG \
--name myapp \
--image myregistry.azurecr.io/myapp:latest \
--registry-login-server myregistry.azurecr.io \
--registry-username <acr-user> \
--registry-password <acr-password> \
--environment-variables APP_ENV=production \
--secure-environment-variables DB_PASSWORD=s3cr3t \
--cpu 2 \
--memory 4
# Logs
az container logs --resource-group myRG --name mycontainer --follow
# Exec into container
az container exec --resource-group myRG --name mycontainer --exec-command "/bin/sh"
# Container group with VNet injection (no public IP)
az container create \
--resource-group myRG \
--name myprivateci \
--image myapp:latest \
--vnet myVNet \
--subnet AciSubnet \
--ip-address Private
Gotchas
- VM stop ≠ deallocate:
az vm stop keeps the VM allocated (still billed). Use az vm deallocate to stop billing.
- VMSS Uniform vs Flexible: Flexible mode is preferred for new deployments — supports mixing instance types and AZs.
- App Service VNET integration: Requires at least Basic plan for regional VNet integration; requires Premium for full outbound VNet routing (
WEBSITE_VNET_ROUTE_ALL=1).
- Functions cold starts: Consumption plan can take 5-15s to cold start. Use Flex or Elastic Premium for latency-sensitive workloads.
- AKS node pool OS disk: Default is Ephemeral OS disk (fast, local SSD) — always prefer this when VM supports it. Managed disk is slower.
- AKS workload identity (preferred over pod identity): Uses OIDC + federated credentials. Never mount service principal secrets in pods.
- Container Apps min-replicas=0: Apps scale to zero when idle (save cost), but first request is slow. Set min-replicas=1 for latency-sensitive apps.
- ACI is not for production HA: No autoscale, no persistent storage across restarts (without Azure Files mount). Use Container Apps or AKS for production.
- Availability Zones ≠ Availability Sets: AZs provide hardware isolation across datacenters; AS provides fault/update domain separation within one datacenter. Prefer AZs.