🖥️ 03 — Deploy and Manage Azure Compute Resources
Domain Weight: 20–25% of exam
Covers ARM templates and Bicep, virtual machines and disks, availability sets and zones, VM Scale Sets, containers, and Azure App Service.
Table of Contents
- 📄 ARM Templates and Bicep
- 🖥️ Create and Configure Virtual Machines
- 📦 Provision and Manage Containers
- 🌐 Create and Configure Azure App Service
- 🔄 Domain 3 Scenario Quick Reference
📄 ARM Templates and Bicep
ARM Template Structure
ARM templates deploy resources declaratively using JSON:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"vmName": {
"type": "string",
"defaultValue": "MyVM",
"metadata": { "description": "Name of the VM" }
}
},
"variables": {
"nicName": "[concat(parameters('vmName'), '-nic')]"
},
"resources": [
{
"type": "Microsoft.Compute/virtualMachines",
"apiVersion": "2024-03-01",
"name": "[parameters('vmName')]",
"location": "[resourceGroup().location]",
"properties": { }
}
],
"outputs": {
"vmId": {
"type": "string",
"value": "[resourceId('Microsoft.Compute/virtualMachines', parameters('vmName'))]"
}
}
}
Key ARM template sections:
| Section | Required | Purpose |
|---|---|---|
$schema |
✅ | Identifies template schema version |
contentVersion |
✅ | Tracks your versioning (e.g. 1.0.0.0) |
parameters |
❌ | Input values at deploy time |
variables |
❌ | Reusable expressions and values |
resources |
✅ | Resources to create/update |
outputs |
❌ | Values returned after deployment |
ARM template functions (common in exam):
1
2
3
4
5
6
concat(...) → concatenate strings
resourceGroup().location → current RG's region
resourceId(...) → construct a resource ID
parameters('name') → reference a parameter
variables('name') → reference a variable
uniqueString(...) → deterministic unique hash
Bicep Equivalent
1
2
3
4
5
6
7
8
9
10
param vmName string = 'MyVM'
var nicName = '${vmName}-nic'
resource vm 'Microsoft.Compute/virtualMachines@2024-03-01' = {
name: vmName
location: resourceGroup().location
properties: {}
}
output vmId string = vm.id
Bicep vs ARM JSON:
| Feature | ARM JSON | Bicep |
|---|---|---|
| Verbosity | High | Low |
dependsOn |
Explicit | Inferred from references |
| Modules | Linked templates | module keyword |
| Type safety | Weak | Strong |
| Preview | N/A | az bicep decompile to convert JSON |
Deploying Templates
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Deploy ARM template to resource group
az deployment group create \
--resource-group MyRG \
--template-file azuredeploy.json \
--parameters vmName=ProdVM
# Deploy Bicep file
az deployment group create \
--resource-group MyRG \
--template-file main.bicep \
--parameters vmName=ProdVM
# What-if (preview changes without deploying)
az deployment group what-if \
--resource-group MyRG \
--template-file main.bicep
# Export existing resources as ARM template
az group export --name MyRG > exported-template.json
Deployment modes:
| Mode | Behaviour |
|---|---|
| Incremental (default) | Only creates/updates resources in template; does not delete extras |
| Complete | Deletes resources in RG not in the template; dangerous! |
⚠️ Exam Caveat: Complete mode deletes resources not defined in the template. Use with extreme caution. The exam may offer Complete mode as a wrong answer for “safely deploy”.
🖥️ Create and Configure Virtual Machines
VM Creation Key Parameters
1
2
3
4
5
6
7
8
9
10
11
12
az vm create \
--resource-group MyRG \
--name MyVM \
--image Ubuntu2204 \
--size Standard_D2s_v3 \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_rsa.pub \
--vnet-name MyVNet \
--subnet MySubnet \
--public-ip-address "" \ # No public IP
--nsg "" \ # No NSG (use existing)
--zone 1 # Deploy to Availability Zone 1
VM Sizes (Families)
| Series | Workload |
|---|---|
| B | Burstable; low baseline, short spikes |
| D | General purpose; balanced CPU/RAM |
| E | Memory optimised; high RAM:CPU |
| F | Compute optimised; high CPU:RAM |
| H | High performance compute; high CPU:RAM |
| L | Storage optimised; high disk throughput |
| M | Memory optimised; Largest memory (up to 4+ TB RAM) |
| N | GPU (NVIDIA); ML, graphics |
⚠️ Exam Caveat: VM size families are regionally available — not every size exists in every region. Check availability before deploying.
VM Disks
| Disk Type | Attachment | Description |
|---|---|---|
| OS Disk | Always 1 | Boot disk; managed by Azure |
| Temporary Disk | Always 1 (most VMs) | Local SSD; D: or /dev/sdb; data lost on deallocation |
| Data Disk | 0 to N | Additional managed disks for data |
Managed disk SKUs:
| SKU | IOPS/Disk | Throughput | Use Case |
|---|---|---|---|
| Standard HDD (S) | Up to 500 | Up to 60 MB/s | Dev/test, infrequent access |
| Standard SSD (E) | Up to 6,000 | Up to 750 MB/s | Web servers, light DB |
| Premium SSD (P) | Up to 20,000 | Up to 900 MB/s | Production, latency-sensitive |
| Premium SSD v2 | Up to 80,000 | Up to 1,200 MB/s | DB workloads without over-provisioning |
| Ultra Disk | Up to 160,000 | Up to 4,000 MB/s | Mission-critical, SAP HANA |
⚠️ Exam Caveat: Temporary disks (
D:on Windows,/dev/sdbon Linux) are lost on stop/deallocation. Do not store data there. Swap/page files are fine.
Azure Disk Encryption (ADE)
ADE encrypts OS and data disks using BitLocker (Windows) or DM-Crypt (Linux) with keys stored in Azure Key Vault.
1
2
3
4
5
6
7
8
9
10
11
12
# Create a Key Vault with disk encryption enabled
az keyvault create \
--name MyKeyVault \
--resource-group MyRG \
--location westeurope \
--enabled-for-disk-encryption true
# Enable ADE on a VM
az vm encryption enable \
--resource-group MyRG \
--name MyVM \
--disk-encryption-keyvault MyKeyVault
⚠️ Exam Caveat: ADE encrypts at the OS level. Server-Side Encryption (SSE) encrypts at the Azure storage level and is always on. These are different layers — both can be active simultaneously.
Moving VMs
VMs can be moved between:
- Resource groups (same subscription)
- Subscriptions (same or different tenant)
- Regions (using Azure Resource Mover)
1
2
3
4
# Move VM to another resource group
az resource move \
--destination-group TargetRG \
--ids /subscriptions/<sub>/resourceGroups/SourceRG/providers/Microsoft.Compute/virtualMachines/MyVM
⚠️ Exam Caveat: Moving a VM also requires moving its dependent resources (NIC, OS disk, public IP). The move operation locks the source and destination resource groups temporarily.
VM Sizes — Resizing
1
2
3
4
5
6
7
8
# List available sizes in a region
az vm list-sizes --location westeurope -o table
# Resize a VM (requires stop/deallocate if new size family)
az vm resize \
--resource-group MyRG \
--name MyVM \
--size Standard_D4s_v3
Availability Options
| Option | SLA | Protects Against |
|---|---|---|
| No redundancy | 99.9% (Premium disk) | — |
| Availability Set | 99.95% | Rack-level hardware failure |
| Availability Zone | 99.99% | Datacenter-level failure |
| VM Scale Sets across zones | 99.99% | Zone failure + auto-scale |
Availability Set internals:
- Fault domains (FD): Separate power and network (up to 3 FDs)
- Update domains (UD): Only one UD is rebooted at a time during platform updates (up to 20 UDs)
⚠️ Exam Caveat: Availability Sets must be created before VMs — you cannot add an existing VM to an availability set. You’d need to recreate the VM.
VM Scale Sets (VMSS)
VMSS automatically creates and scales identical (or mixed) VM instances.
1
2
3
4
5
6
7
8
9
az vmss create \
--resource-group MyRG \
--name MyScaleSet \
--image Ubuntu2204 \
--instance-count 3 \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_rsa.pub \
--upgrade-policy-mode Automatic \
--zones 1 2 3
Orchestration modes:
| Mode | Description |
|---|---|
| Uniform Orchestration | Optimized for large-scale workloads with identical virtual machine instances |
| Flexible Orchestration | Optimized for high availability and scalability with identical or mixed virtual machine types |
Scaling modes:
| Mode | Description |
|---|---|
| Manual | You set the instance count manually |
| Custom autoscale | Rules based on metrics (CPU, memory, custom) |
| Scheduled | Scale at defined times |
Upgrade policies:
| Policy | Behaviour |
|---|---|
| Automatic | Azure updates instances immediately |
| Rolling | Updates instances in batches |
| Manual | You update each instance explicitly |
📦 Provision and Manage Containers
Azure Container Registry (ACR)
ACR is a private Docker registry hosted in Azure.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Create an ACR
az acr create \
--resource-group MyRG \
--name myregistry \
--sku Basic \
--admin-enabled false
# Build and push an image
az acr build \
--registry myregistry \
--image myapp:v1 .
# Pull an image
docker pull myregistry.azurecr.io/myapp:v1
ACR SKUs:
| SKU | Storage | Features |
|---|---|---|
| Basic | 10 GB | Dev/test; no geo-replication |
| Standard | 100 GB | Most production workloads |
| Premium | 500 GB | Geo-replication, private endpoints, content trust |
⚠️ Exam Caveat: Authenticating to ACR from other Azure services (ACI, AKS, App Service) should use Managed Identity or a service principal, not admin credentials.
Azure Container Instances (ACI)
ACI runs containers serverlessly — no VM management required.
1
2
3
4
5
6
7
8
9
10
11
az container create \
--resource-group MyRG \
--name mycontainer \
--image myregistry.azurecr.io/myapp:v1 \
--cpu 1 \
--memory 1.5 \
--registry-login-server myregistry.azurecr.io \
--registry-username $(az acr credential show -n myregistry --query username -o tsv) \
--registry-password $(az acr credential show -n myregistry --query passwords[0].value -o tsv) \
--dns-name-label myapp-unique \
--ports 80
- ACI supports Linux and Windows containers
- Billed per second (CPU + Memory)
- Supports container groups (multiple containers in one host, share network)
Azure Container Apps (ACA)
ACA is a managed container platform built on Kubernetes for running microservices and APIs.
| Feature | ACI | ACA |
|---|---|---|
| Use case | Single containers, batch | Microservices, APIs, background workers |
| Scaling | Manual | Auto-scale to zero (Keda-based) |
| Ingress | DNS label | Built-in HTTPS ingress |
| Revisions | N/A | Rolling updates with traffic splitting |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Create a Container Apps environment
az containerapp env create \
--name MyEnv \
--resource-group MyRG \
--location westeurope
# Deploy a container app
az containerapp create \
--name myapp \
--resource-group MyRG \
--environment MyEnv \
--image myregistry.azurecr.io/myapp:v1 \
--target-port 80 \
--ingress external \
--min-replicas 1 \
--max-replicas 5
Scaling rules in ACA: HTTP traffic, CPU/Memory, Azure Service Bus queue length, and custom KEDA triggers.
⚠️ Exam Caveat: ACA can scale to zero replicas — cost drops to $0 for idle apps. ACI does not scale automatically. AKS is the full Kubernetes experience (not covered in AZ-104 in depth).
🌐 Create and Configure Azure App Service
App Service Plans
The App Service Plan defines the region, number of workers, VM size, and pricing tier.
Pricing tiers:
| Tier | CPU/RAM | Custom Domain | SSL | Staging / Deployment Slots | Scale-Out |
|---|---|---|---|---|---|
| Free (F1) | Shared | ❌ | ❌ | 0 | ❌ |
| Basic (B1-B3) | Dedicated | ✅ | ✅ | 0 | Manual (up to 3) |
| Standard (S1-S3) | Dedicated | ✅ | ✅ | 5 | Auto |
| Premium v3 (P1-P3) | Dedicated | ✅ | ✅ | 20 | Auto |
| Isolated v2 (I1-I3) | Dedicated VNet | ✅ | ✅ | 20 | Auto |
1
2
3
4
5
6
# Create App Service Plan
az appservice plan create \
--name MyPlan \
--resource-group MyRG \
--sku P1v3 \
--is-linux
Creating and Configuring an App Service
1
2
3
4
5
6
# Create web app (Linux, Node.js)
az webapp create \
--resource-group MyRG \
--plan MyPlan \
--name mywebapp-unique \
--runtime "NODE:20-lts"
Certificates and TLS
- Free managed certificate: App Service provides a free TLS cert for custom domains (cannot be exported)
- App Service Certificate: Purchased and managed through Azure; can be used across apps
- Uploaded certificate: Upload your own .pfx certificate
1
2
3
4
5
6
7
8
9
10
11
# Enforce HTTPS
az webapp update \
--resource-group MyRG \
--name mywebapp-unique \
--https-only true
# Set minimum TLS version
az webapp config set \
--resource-group MyRG \
--name mywebapp-unique \
--min-tls-version 1.2
Custom DNS Mapping
To map www.contoso.com to an App Service:
- Add a CNAME record:
www → mywebapp-unique.azurewebsites.net - Verify domain ownership with a
asuidTXT record - Add the custom domain in the portal:
App Service → Custom Domains → Add custom domain
1
2
3
4
az webapp config hostname add \
--webapp-name mywebapp-unique \
--resource-group MyRG \
--hostname www.contoso.com
Backup for App Service
- Backups include: app content, configuration, and linked database (optional)
- Stored in an Azure Storage Account as a ZIP file
- Requires Standard tier or higher
1
2
3
4
az webapp config backup create \
--resource-group MyRG \
--webapp-name mywebapp-unique \
--container-url "https://mystorageacct.blob.core.windows.net/backups?<SAS>"
Networking Settings for App Service
| Feature | Direction | Description |
|---|---|---|
| VNet Integration | Outbound | App calls resources in VNet |
| Private Endpoint | Inbound | App accessed privately from VNet |
| Access Restrictions | Inbound | IP-based allow/deny rules |
| Service Endpoints | Outbound | Secure calls to Azure PaaS from VNet |
Deployment Slots
Deployment slots allow blue/green deployments — deploy to a staging slot, test, then swap to production.
- Standard plan: 5 slots; Premium: 20 slots
- Slot swap: App configuration is also swapped (sticky settings excluded)
- Sticky settings: App settings/connection strings marked sticky are NOT swapped
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Create a deployment slot
az webapp deployment slot create \
--name mywebapp-unique \
--resource-group MyRG \
--slot staging
# Deploy to staging slot
az webapp deploy \
--resource-group MyRG \
--name mywebapp-unique \
--slot staging \
--src-path ./app.zip
# Swap staging to production
az webapp deployment slot swap \
--resource-group MyRG \
--name mywebapp-unique \
--slot staging \
--target-slot production
⚠️ Exam Caveat: Deployment slots are available from Standard tier and above. The Free and Basic tiers do not support slots. Auto-swap can be configured so a successful deployment to staging automatically swaps to production.
🔄 Domain 3 Scenario Quick Reference
| Scenario | Solution |
|---|---|
| Deploy multiple identical environments from code | ARM template or Bicep with parameters |
| Protect production VMs from a single datacenter failure | Deploy VMs across Availability Zones |
| Scale a web tier automatically based on CPU load | Configure VM Scale Set with autoscale rules |
| Run a short-lived container task without managing infrastructure | Azure Container Instances (ACI) |
| Deploy a microservices API that scales to zero when idle | Azure Container Apps (ACA) |
| Blue/green deployment for a web app | Create a deployment slot, deploy, then swap |
| Encrypt VM disks with company-controlled keys | Enable Azure Disk Encryption (ADE) with Key Vault |
| Map a custom domain to an App Service | Add CNAME/A record in DNS + Add custom domain in portal |
| Preview ARM template changes without deploying | Use az deployment group what-if |
| Allow App Service to access a SQL database in a private VNet | Enable VNet Integration on the App Service |