Chapter 3
Deploy and Manage Azure Compute Resources
Compute is the engine room of Azure. Every workload you will ever administer — virtual machines, containers, web applications — runs on compute, and the AZ-104 exam devotes roughly a fifth to a quarter of its questions to it. This chapter covers the full lifecycle: automating deployments with ARM templates and Bicep, creating and managing virtual machines, choosing the right container service, and running web applications on App Service.
Automate Deployments with ARM Templates and Bicep

Clicking through the Azure portal works for a demo. It does not work for production. Real Azure administrators define infrastructure as code: version-controlled, reviewable, repeatable declarations of what should exist. In Azure, that means ARM templates (JSON) and Bicep (a simpler language that compiles to ARM). The exam expects you to read both, predict what a deployment will do, and choose the right deployment options.
Anatomy of an ARM template
An ARM template is a JSON file with a fixed structure. You need to recognize each section:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"vmName": { "type": "string", "defaultValue": "webvm01" }
},
"variables": {
"vnetName": "[concat(parameters('vmName'), '-vnet')]"
},
"resources": [
{
"type": "Microsoft.Network/virtualNetworks",
"apiVersion": "2023-09-01",
"name": "[variables('vnetName')]",
"location": "[resourceGroup().location]",
"properties": { "...": "..." }
}
],
"outputs": {
"vnetId": { "type": "string", "value": "[resourceId('Microsoft.Network/virtualNetworks', variables('vnetName'))]" }
}
}
- parameters: values supplied at deployment time (names, sizes, passwords). Mark secrets with
"type": "securestring". - variables: values computed once inside the template, reused in multiple places.
- resources: the actual Azure resources to create, each with a
type,apiVersion,name, andlocation. - outputs: values returned after deployment, useful for chaining deployments.
Every resource in a template can also declare dependsOn, which forces ordering — for example, a virtual machine depends on its network interface. Without dependsOn, Azure deploys resources in parallel wherever possible, which is faster but can fail if one resource needs another to exist first.
In an ARM template, dependsOn controls deployment order. If a template deploys a VM and its NIC with no dependsOn, Azure deploys them in parallel and the VM deployment may fail. Look for missing dependencies in scenario questions.
Deployment modes: Incremental vs Complete
When you deploy a template to a resource group, you choose a mode. This is one of the most-tested concepts in the entire exam.
- Incremental (the default): Azure adds new resources and updates existing ones to match the template. Resources already in the resource group that are not in the template are left untouched. This is the safe, everyday mode.
- Complete: Azure makes the resource group match the template exactly. Any resource in the group that is not defined in the template gets deleted. This is how you enforce "the template is the truth," but it is destructive if you point it at the wrong scope.
Key facts the exam loves: Complete mode only works at the resource group scope — you cannot use Complete mode at subscription, management group, or tenant scope (those deployments are always incremental). Complete mode never deletes the resource group itself, only the resources inside it. And child resources follow their parent: if the template defines a virtual network but not its subnets, Complete mode will delete the "extra" subnets because they are not in the template.
Incremental = add/update only, never deletes. Complete = deletes anything in the resource group that is not in the template. Complete mode is resource-group scope only. If a question says "no existing resources may be deleted," the answer is Incremental.
Deploy with the CLI like this:
# Incremental (default)
az deployment group create \
--resource-group rg-web-prod \
--template-file webapp.json \
--parameters vmName=webvm01 adminPassword=$ADMIN_PW
# Complete mode — destructive, think twice
az deployment group create \
--resource-group rg-web-prod \
--template-file webapp.json \
--mode Complete
Preview changes with what-if
Before you deploy — especially in Complete mode — run a what-if operation. It shows exactly what the deployment would do (create, modify, delete, ignore) without changing anything:
az deployment group what-if \
--resource-group rg-web-prod \
--template-file webapp.json \
--parameters vmName=webvm01
The output lists each resource with a predicted change type: Create, Modify, Delete, Ignore, or NoChange. You can also force a what-if review before every deployment with --confirm-with-what-if, which pauses and asks for confirmation after showing the preview.
what-if predicts Create/Modify/Delete/Ignore/NoChange without deploying anything. It is the correct answer whenever a question asks how to "preview" or "verify" changes before deploying a template.
Bicep: the same engine, less pain
Bicep is a domain-specific language that compiles (transpiles) directly into ARM JSON. Everything you can do in ARM, you can do in Bicep — with far less boilerplate, no bracket soup, and better tooling. Microsoft's direction is clear: new automation should be written in Bicep. The exam tests Bicep syntax, so learn to read it.
@description('The name of the virtual machine.')
param vmName string = 'webvm01'
@allowed(['Standard_B2s', 'Standard_D2s_v5'])
param vmSize string = 'Standard_B2s_v5'
@secure()
param adminPassword string
var vnetName = '${vmName}-vnet'
var location = resourceGroup().location
resource vnet 'Microsoft.Network/virtualNetworks@2023-09-01' = {
name: vnetName
location: location
properties: {
addressSpace: { addressPrefixes: ['10.0.0.0/16'] }
}
}
resource vm 'Microsoft.Compute/virtualMachines@2023-09-01' = {
name: vmName
location: location
properties: {
hardwareProfile: { vmSize: vmSize }
// ...
}
}
Essential Bicep syntax for the exam:
- Parameters (
param): inputs with types (string,int,bool,array,object,secureString). Default values make them optional. - Decorators (the
@lines): metadata and constraints.@description()documents,@allowed()restricts to a list of values,@secure()marks a secret (never logged or returned),@minValue()/@maxValue()bound numbers. - Variables (
var): computed once, reused. String interpolation uses${}. forloops: create multiple resources or properties from an array — the Bicep replacement for ARM'scopy:
param subnetNames array = ['web', 'app', 'db']
resource subnets 'Microsoft.Network/virtualNetworks/subnets@2023-09-01' = [for name in subnetNames: {
name: name
// ...
}]
ifconditions: deploy a resource only when a condition is true:
param deployBastion bool = false
resource bastion 'Microsoft.Network/bastionHosts@2023-09-01' = if (deployBastion) {
// ...
}
- Modules: Bicep files that deploy other Bicep files, letting you compose and reuse infrastructure. A module has its own params and outputs.
existingkeyword: references a resource that already exists (created outside this deployment) so you can read its properties or deploy children under it — without Bicep trying to create or manage it:
resource existingVnet 'Microsoft.Network/virtualNetworks@2023-09-01' existing = {
name: 'prod-vnet'
}
Compile and deploy:
az bicep build --file main.bicep # compile to main.json (ARM)
az bicep decompile --file legacy.json # best-effort reverse: ARM -> Bicep
az deployment group create --resource-group rg-web-prod --template-file main.bicep
Note that az deployment group create accepts a .bicep file directly — Azure transpiles it during deployment. You can also keep deployment-time values in a .bicepparam file, which is the Bicep-native replacement for ARM parameter JSON files.
Know what each Bicep keyword does: for = loops, if = conditional deployment, existing = reference without managing, modules = composition. @secure() prevents a parameter value from being logged. az bicep decompile converts ARM JSON back to Bicep (best effort, not perfect).
Template functions you must know
Both ARM and Bicep share a library of functions. Two appear constantly on the exam:
uniqueString(): generates a deterministic hash from its inputs — the standard way to create globally unique names (storage accounts, key vaults) that are still reproducible across deployments:
var storageName = 'st${uniqueString(resourceGroup().id)}'
Same inputs always produce the same 13-character string. It is not random.
resourceId(): builds the full resource ID of a resource, used when one resource needs to reference another (a VM referencing its NIC, a diagnostic setting referencing a Log Analytics workspace).
Others worth recognizing: reference() and listKeys() (retrieve runtime values like storage keys at deploy time — listKeys() requires the deployment identity to have key access), concat(), resourceGroup().location (keeps resources in the same region as the group), and deployment().name.
Exporting templates
Already have resources built in the portal and want them as code? Select the resource group in the portal and choose Export template (under Automation), or run:
az group export --name rg-web-prod > exported.json
The export is a starting point, not a finished product: it captures current state verbatim, including hardcoded names and sometimes properties you would parameterize. Clean it up — replace literals with parameters and variables — before treating it as your source of truth.
Worked scenario: deploying a web tier with Bicep
Situation: You must deploy 20 identical web servers across three subnets for a new application. The security team requires every deployment to be previewed before it runs, and no existing resource in the target resource group may be deleted.
Reasoning, step by step:
- Choose the language. Bicep is the right call: less boilerplate than ARM for 20 near-identical VMs, and
az deployment group createaccepts.bicepdirectly. - Choose the mode. "No existing resource may be deleted" rules out Complete mode immediately. Use Incremental (the default) — it adds the 20 VMs and leaves everything else alone.
- Preview first. The security requirement means running
az deployment group what-ifand reviewing theCreatelist before the real deployment — or adding--confirm-with-what-ifto the deploy command. - Structure the Bicep. A
param vmCount int = 20, aforloop over the count to create NICs and VMs,uniqueString(resourceGroup().id)for unique storage/diagnostic names, and@secure()on the admin password parameter. - Deploy.
az deployment group create --resource-group rg-web-prod --template-file webtier.bicepin Incremental mode.
The exam rewards this exact chain of reasoning: mode selection from the "do not delete" constraint, what-if from the "preview" requirement, and for loops from the "many identical resources" requirement.
Virtual Machines: From Creation to Day-Two Operations

Virtual machines are the most flexible — and most hands-on — compute option in Azure. As an administrator you are responsible for the full VM lifecycle: choosing sizes, configuring availability, managing disks, patching, resizing, and eventually decommissioning. The exam tests all of it, with heavy emphasis on availability options and disk management.
Creating VMs: portal, CLI, and PowerShell
The portal wizard walks you through the essentials: subscription, resource group, name, region, image (Windows Server, Ubuntu, and others), size, administrator credentials, inbound ports, and disks. For repeatable work, script it.
Azure CLI:
az vm create \
--resource-group rg-web-prod \
--name webvm01 \
--image Ubuntu2204 \
--size Standard_D2s_v5 \
--admin-username azureadmin \
--generate-ssh-keys \
--vnet-name prod-vnet \
--subnet web-subnet \
--nsg web-nsg \
--public-ip-address "" \
--os-disk-size-gb 128
Note --public-ip-address "" — in production you usually skip the public IP and reach the VM through Bastion or a load balancer. --generate-ssh-keys creates an SSH key pair for Linux VMs.
PowerShell:
$cred = Get-Credential # prompts for admin username/password
New-AzVm `
-ResourceGroupName "rg-web-prod" `
-Name "webvm01" `
-Location "eastus" `
-Image "Win2022Datacenter" `
-Size "Standard_D2s_v5" `
-Credential $cred `
-VirtualNetworkName "prod-vnet" `
-SubnetName "web-subnet"
After creation, common day-one tasks include installing the Azure VM Agent (preinstalled on marketplace images — it enables extensions), joining a domain, and attaching data disks.
Availability options: sets, zones, and scale sets
Hardware fails. Azure datacenters do maintenance. Your job is to design so that neither event takes the application down. Three mechanisms, three different promises:
Availability sets protect against failures within a single datacenter:
- Fault domains (2 or 3 per region): groups of VMs sharing a common power source and network switch — essentially, separate racks. VMs spread across fault domains survive a rack-level failure.
- Update domains (up to 20, default 5): groups updated together during planned Azure maintenance. VMs spread across update domains survive host patching because only one update domain reboots at a time.
- SLA: 99.95% for two or more VMs in an availability set. All VMs in a set must be the same size series, and you assign the set at creation — you cannot move an existing VM into an availability set later.
Availability zones protect against datacenter-level failure. Each Azure region with zones has three physically separate datacenters (Zone 1, 2, 3) with independent power, cooling, and networking. Spread VMs across zones and you get 99.99% SLA. Zonal VMs keep their zone assignment for life — you cannot change a VM's zone after creation; you would redeploy.
Virtual Machine Scale Sets (VMSS) manage fleets of identical VMs with autoscaling and rolling upgrades:
- Uniform orchestration (the classic mode): all instances share one VM configuration; best for stateless, truly identical workloads.
- Flexible orchestration: mixes availability-zone/domain spreading with per-VM individuality — you can attach existing VMs, mix SKUs, and get high availability with more control. This is the mode Microsoft now recommends for most new scale sets.
Fault domains = unplanned hardware failure (racks). Update domains = planned maintenance (reboot groups, up to 20). Two VMs in an availability set = 99.95% SLA; VMs across zones = 99.99%. You cannot add a VM to an availability set or change its zone after creation — both are set-at-birth decisions.
VM sizes and disk types
Sizes follow a letter convention worth knowing: B (burstable, cheap, for variable workloads), D (general purpose, good CPU-to-memory ratio), E (memory optimized), F (compute optimized), plus specialty families (GPU: N-series; high-performance computing: H-series). The s suffix (e.g., Standard_D2s_v5) means Premium Storage capable. Newer generations carry version numbers (_v5).
Disks. Every VM has one OS disk; you can attach data disks (the count depends on VM size). All are managed disks — Azure handles the storage accounts behind the scenes. Four tiers:
| Disk type | Best for | Key facts |
|---|---|---|
| Standard HDD | Backup, infrequent access | Cheapest, spinning-disk performance |
| Standard SSD | Web servers, light production | Consistent performance, low cost |
| Premium SSD v1 | Production databases, high I/O | Single-digit ms latency, provisioned IOPS/throughput per disk size (P1–P80) |
| Premium SSD v2 | Highest-performance workloads | Sub-ms latency, independently scalable IOPS and throughput, pay for what you provision |
| Ultra Disk | Extreme I/O (SAP HANA, top-tier SQL) | Highest IOPS/throughput, configurable performance, limited regional availability |
Two exam-critical disk facts: Ultra Disk cannot be used as an OS disk (data disks only), and disk performance for Premium SSD v1 is tied to the disk size you provision — a bigger P-disk buys more IOPS, which is why right-sizing disks matters for database performance. Disk encryption options (Azure Disk Encryption with BitLocker/DM-Crypt, encryption at host, and customer-managed keys) let you meet compliance requirements.
Snapshots, images, and extensions
Snapshots are point-in-time, read-only copies of a managed disk — your quick rollback before a risky change. A full snapshot copies the entire disk; an incremental snapshot stores only the changes since the last snapshot and is billed only for the delta, making it far cheaper for repeated backups. You can create a new disk (or a VM) from a snapshot.
Images capture a VM for redeployment, and the distinction the exam tests is:
- Generalized image: the OS has been prepared for cloning —
sysprepon Windows,waagent -deprovisionon Linux — stripping machine identity (SID, hostname). Deploy as many fresh VMs as you want from it. - Specialized image: captured without preparation. It retains the original machine identity and is suitable for restoring that specific VM, not for cloning fleets.
VM extensions add post-deployment capabilities via the VM agent. The one you will use most is the Custom Script Extension: it downloads and runs scripts (PowerShell, Bash) on the VM — perfect for installing software or joining a domain at deploy time. Only one Custom Script Extension instance runs per VM, and extension execution status is visible in the portal under the VM's Extensions blade.
Moving and resizing VMs
Moving a VM between resource groups or subscriptions (same tenant) is a metadata operation — the VM keeps running, and you do it from the portal (select VM → Move) or CLI. Moving across regions is different: there is no in-place region move. You recreate the VM in the target region, typically with Azure Site Recovery replication or by capturing an image/snapshot and redeploying.
Resizing changes the VM's size (and therefore its CPU, memory, and NIC/disk limits). The gotcha: a VM can only resize to sizes available on its current physical hardware cluster. If the target size is not available there, the resize fails and you must deallocate first — deallocate releases the hardware lease, letting Azure place the VM on a new cluster on next start:
az vm deallocate --resource-group rg-web-prod --name webvm01
az vm resize --resource-group rg-web-prod --name webvm01 --size Standard_D4s_v5
az vm start --resource-group rg-web-prod --name webvm01
Resize fails with a "size not available" error → deallocate, resize, start. Moving a VM between resource groups or subscriptions is non-disruptive; moving between regions requires re-creation. You cannot change a VM's availability zone or add it to an availability set after creation.
Spot VMs and Dedicated Hosts
Azure Spot Virtual Machines let you bid on unused Azure capacity at discounts up to 90%. The trade: Azure can evict your VM at any time when it needs the capacity back, with only a 30-second notice. You choose the eviction policy — Deallocate (stop, keep disks, resume later) or Delete (remove everything). Spot is ideal for fault-tolerant, interruptible work: batch processing, rendering, dev/test, and stateless scale-out tiers. It is the wrong choice for anything stateful or SLA-bound.
Azure Dedicated Hosts are the opposite philosophy: you reserve an entire physical server in an Azure datacenter, and only your organization's VMs run on it. Reasons to use them: hardware isolation for compliance, and licensing — Azure Hybrid Benefit lets you apply existing Windows Server and SQL Server licenses to dedicated hosts, which can significantly cut costs. Hosts are organized in host groups (per region, per fault-domain count), and you assign VMs to specific hosts for placement control.
Worked scenario: the failed resize
Situation: An administrator tries to resize webvm01 from Standard_D2s_v5 to Standard_E4s_v5 in the portal. The operation fails: "The requested VM size is not available in the current region/cluster." The application team needs the extra memory tonight.
Reasoning, step by step:
- Interpret the error. The size exists in the region (E-series is standard), so the problem is the current hardware cluster backing this VM — E-series hosts are not in it.
- Recall the rule. A running (allocated) VM can only move to sizes on its current cluster. To escape the cluster, the VM must be deallocated, which releases the hardware lease.
- Plan for downtime. Deallocate stops the VM — unlike a normal stop, it also releases the public IP unless it is static, and compute billing stops. Schedule a brief maintenance window and warn the app team.
- Execute. Deallocate → resize to
Standard_E4s_v5→ start. On start, Azure's fabric places the VM on a cluster with E-series capacity. - Verify. Confirm the new size in the portal, check the application comes up, and confirm the (static) IP is unchanged.
This is a classic exam scenario because it chains three facts: the deallocate-first rule, the difference between stop and deallocate, and the static-IP precaution.
VM Networking Essentials for Administrators

Virtual networking gets its own deep dive in Chapter 4. Here is the compute-side minimum you need: every VM has at least one network interface (NIC), and the NIC is where IP configuration and security policy attach.
- A NIC lives in exactly one subnet and carries one primary private IP (static or dynamic) plus optional secondary IPs. Larger VM sizes support multiple NICs (check the size's limits before assuming).
- Accelerated networking (SR-IOV) bypasses the virtual switch for lower latency and higher throughput — enable it on supported VM sizes and OS versions when network performance matters. Plan for it up front: turning it on later requires deallocating the VM.
- Network Security Groups (NSGs) associate to the NIC, the subnet, or both. When both exist, both are evaluated — traffic must pass the subnet NSG and the NIC NSG. A common troubleshooting finding: the subnet NSG allows traffic that the NIC NSG blocks.
NSG on the subnet + NSG on the NIC = both must allow the traffic. If a VM cannot be reached, check both associations. Accelerated networking is a NIC-level setting — enabling it on an existing VM requires deallocating the VM first, so plan for it at design time.
Containers: ACR, ACI, and Container Apps

Containers package an application with its dependencies so it runs identically anywhere. Azure offers three managed container services, and the exam relentlessly tests whether you can pick the right one. Learn the decision tree, not just the definitions.
Azure Container Registry (ACR)
ACR is a private Docker registry — where you store and manage container images. Three SKUs:
- Basic: entry-level (10 GB storage), suitable for dev/test.
- Standard: production throughput (100 GB storage), same features as Basic at higher limits.
- Premium (500 GB): adds geo-replication (push once, pull from the nearest region), content trust (image signing), private link connectivity, scoped tokens (fine-grained, per-repository credentials), retention policies, and availability zones.
ACR Tasks automate image builds and maintenance: build images on code commit (quick tasks), on a schedule, or on base-image updates — so when a base OS image is patched, your application images rebuild automatically. Multi-step tasks can build, test, and push in one definition.
az acr create --resource-group rg-containers --name myregistry --sku Premium
az acr build --registry myregistry --image webapp:v1 .
Geo-replication, content trust, private link, and scoped tokens are Premium-only ACR features. ACR Tasks rebuild images automatically when base images update. If a question demands pulling images from the closest region worldwide, the answer is Premium with geo-replication.
Azure Container Instances (ACI)
ACI runs containers serverlessly — no VMs, no orchestrator to manage. You define a container group (one or more containers sharing a lifecycle, local network, and storage volumes), and Azure runs it, billing per second.
- Restart policies:
Always(default — keep it running, like a service),OnFailure(rerun only if it exits with an error),Never(run once to completion — the right choice for batch jobs). - Use cases: event-driven workloads, batch jobs, CI/CD agents, quick prototypes, bursting beyond AKS capacity.
- Container groups can join a virtual network via a delegated subnet, mount Azure Files shares for persistent storage, and request GPU SKUs (limited regions) for inference workloads.
ACI's limits are its simplicity: no built-in load balancing across groups, no rolling updates, no service discovery. When you outgrow one container group, you have outgrown ACI.
Azure Container Apps
Container Apps is the middle ground: serverless containers with superpowers, built on Kubernetes but without exposing it. Key concepts:
- Environment: the secure boundary around your apps. It provides the virtual network integration, logging (Log Analytics), and workload profiles. One environment hosts many apps.
- Revisions: immutable snapshots of your app. Single revision mode runs one active revision (simple services); multiple revision mode runs several simultaneously with traffic splitting — the native way to do blue/green or A/B deployments.
- Scaling: event-driven via KEDA scalers (queue length, CPU, HTTP concurrency, timers, and many more). Set min replicas to 0 and the app scales to zero when idle — you pay nothing while it sleeps. Ingress can be external (public HTTPS with a managed certificate) or internal (environment-only).
- Dapr integration gives microservices building blocks (service invocation, pub/sub, state management, bindings) as a sidecar, without baking SDKs into your code.
- Secrets are stored at the app level and referenced by containers — never hardcode credentials in images.
Choosing: ACI vs Container Apps vs AKS
This decision appears on the exam in multiple disguises. Memorize the ladder:
| Need | Choose |
|---|---|
| Run a container quickly, no orchestration, per-second billing | ACI |
| Serverless containers + autoscaling to zero + revisions/traffic splitting + Dapr microservices | Container Apps |
| Full Kubernetes API, custom operators, advanced networking/service mesh, massive scale, multi-tenant clusters | AKS (Azure Kubernetes Service) |
Rules of thumb: if the question mentions "without managing infrastructure" and scaling/traffic splitting, it is Container Apps, not ACI. If it mentions the Kubernetes API, kubectl, or pod-level control, it is AKS. If it is a simple batch job or burst workload, ACI wins on simplicity.
ACI = simplest, single container groups, per-second billing. Container Apps = serverless + KEDA autoscaling (including scale-to-zero) + revisions with traffic splitting + Dapr. AKS = full Kubernetes control. "Event-driven, scales to zero" screams Container Apps.
Worked scenario: choosing the container service
Situation: A retail company needs an image-processing pipeline. Photos land in a storage queue; each photo must be resized within seconds; traffic spikes 50x on sale days and drops to near zero overnight. The team has no Kubernetes expertise and wants zero infrastructure to manage.
Reasoning, step by step:
- Eliminate AKS. No Kubernetes expertise on the team, and managing clusters contradicts "zero infrastructure."
- ACI or Container Apps? ACI handles event-driven work, but each spike would need manual group management, and there is no built-in queue-driven autoscaling or scale-to-zero across a fleet.
- Match to Container Apps. KEDA scalers react to queue length automatically; min replicas 0 means no overnight cost; revisions allow safe rollout of a new image-processing version with traffic splitting for canary testing.
- Supporting services. Images stored in ACR Premium (geo-replication puts images near each region's Container Apps environment); secrets (storage connection strings) in Container Apps secrets, not in the image.
The exam tests this pattern — queue-driven, spiky, serverless, no K8s skills — because Container Apps is unambiguously the answer.
Azure App Service: Web Apps Done Right

App Service is Azure's fully managed platform for web applications — you bring the code, Azure handles the OS patching, load balancing, and scaling. It hosts Web Apps, API apps, and mobile backends in dozens of language stacks (.NET, Java, Node.js, Python, PHP, Ruby). As an administrator, your responsibilities are the plan, deployment, domains/TLS, backup, and scaling.
Plans and tiers: scale up vs scale out
Every App Service app runs in an App Service plan, which defines the region, VM size, and feature set — and the plan's cost is shared by all apps in it. Tiers:
- Free (F1) / Shared (D1): dev/test only. No SLA, no scaling, no custom domains (Shared allows them), no slots.
- Basic (B1–B3): first production-capable tier. Custom domains, manual scale-out, Always On, backups.
- Standard (S1–S3): adds deployment slots (5), autoscale, Traffic Manager integration, daily backups.
- Premium v2 / Premium v3 (P1v2–P3v3): faster hardware, more slots (20), higher scale-out limits, zone redundancy (P1v3+).
- Isolated (I1–I3) / Isolated v2: runs inside an App Service Environment (ASE) — your apps on dedicated VMs in your virtual network. Required for strict network isolation and the highest scale limits (up to 100 instances).
Two scaling verbs the exam distinguishes sharply:
- Scale up: change the plan to a bigger tier (B1 → S1 → P1v3). More CPU/memory per instance. Causes a brief restart.
- Scale out: add more instances of the same tier (1 → 5 instances). Traffic is load-balanced across them. This is the elasticity move — and with autoscale (Standard and above), Azure adds or removes instances automatically based on rules you define: metric thresholds (CPU > 70% for 10 minutes → add 2 instances), schedules (scale out every weekday at 8 AM), or a mix.
# Scale out manually
az appservice plan update --name myplan --resource-group rg-web --number-of-workers 4
# Autoscale is configured with monitor autoscale rules against the plan
az monitor autoscale create --resource-group rg-web \
--resource myplan --resource-type Microsoft.Web/serverfarms \
--name autoscale-web --min-count 2 --max-count 8 --count 2
Scale UP = bigger tier (vertical). Scale OUT = more instances (horizontal). Autoscale needs Standard tier or higher. If a question says "handle load automatically," the answer involves scale-out/autoscale, not scale-up.
Deploying web apps
Deployment Center connects your app to a source: GitHub Actions, Azure DevOps, Bitbucket, local Git, or FTP/S. For production, prefer GitHub Actions or Azure DevOps pipelines — every push builds, tests, and deploys with full audit history. The Kudu engine (the https://<app>.scm.azurewebsites.net site) powers deployments, file browsing, and diagnostic logs behind the scenes.
Application settings to know: Always On (Basic+ — keeps the app loaded instead of unloading after idle; required for WebJobs and functions that must stay warm), ARR affinity (sticky sessions to one instance — disable for stateless apps), Health check (App Service pings a path and removes unhealthy instances from the load balancer), and connection strings (stored separately from app settings so code can read them by name).
Deployment slots: swap with confidence
Deployment slots are separate live apps with their own hostnames, tied to one Web App — the classic example is a staging slot alongside production. Deploy to staging, warm it up, test it, then swap: Azure flips the virtual IP routing so staging becomes production in seconds, with zero downtime and instant rollback (swap back).
Swap with preview (multi-phase swap) adds safety for mission-critical apps: phase one applies production settings to staging for a final check; you then complete or cancel the swap manually.
Sticky settings (slot settings): by default, swapping exchanges all settings. Mark an app setting or connection string as a "deployment slot setting" and it stays with its slot — the canonical example is a database connection string: staging keeps pointing at the test database and production at the live one, even after a swap. Forgetting this is how staging apps accidentally write to production databases.
# Create a staging slot and swap it into production
az webapp deployment slot create --name mywebapp --resource-group rg-web --slot staging
az webapp deployment slot swap --name mywebapp --resource-group rg-web \
--slot staging --target-slot production
Sticky (slot) settings do NOT swap — everything else does. Connection strings for per-environment databases must be sticky. Swap with preview = two-phase swap with a manual approval gate. Slots require Standard tier or higher.
Custom domains and TLS/SSL
Bringing your own domain requires Shared tier or higher (Free tier cannot do custom domains). Two DNS patterns:
- Subdomain (
www.contoso.com): point a CNAME record at<app>.azurewebsites.netand verify ownership. - Apex/root domain (
contoso.com): DNS does not allow CNAME at the apex, so create an A record pointing at the app's inbound IP plus a TXT record for verification.
For HTTPS you need a certificate, with two binding types: SNI SSL (the modern standard — multiple certificates on one IP, works with all current browsers) and IP SSL (dedicates a public IP per certificate, only for legacy clients that lack SNI support). Your options for obtaining one:
- Upload your own PFX certificate (from any CA) — full control, supports wildcards.
- App Service managed certificate: free, auto-renewed by Azure — but with limits the exam tests: no wildcard certificates and no apex/naked-domain support. Perfect for
wwwsubdomains, wrong for*.contoso.comor barecontoso.com. - App Service Certificate (paid, via Azure): orderable in the portal, supports wildcards, stored in Key Vault.
Harden TLS with HTTPS Only (redirects all HTTP to HTTPS) and minimum TLS version (set 1.2; older versions are insecure). Certificates the app code must read (client certificates for mutual TLS) are made available via the WEBSITE_LOAD_CERTIFICATES app setting.
Managed certificates are free but cannot do wildcards or apex domains. SNI SSL = modern default; IP SSL = legacy clients only. Custom domains need Shared tier or above. For an apex domain you need an A record plus a TXT verification record.
Backup, ASE basics, and putting it together
Backup (Standard tier and above): configure scheduled backups (daily, with retention) or trigger manual ones. Backups capture your app files and linked databases (via connection strings), and restore can target the same app or a different one (great for cloning environments). The backup storage account must be in the same subscription as the app.
App Service Environment (ASE) runs App Service plans on dedicated compute inside your virtual network — the answer when compliance demands network isolation, private internal load balancing (ILB ASE), or scale beyond public multi-tenant limits. It requires the Isolated v2 tier and carries the highest cost and longest provisioning time of any option here — recommend it only when the requirements genuinely demand it.
A quick architecture recap for the exam: put the plan in the right region near your users, front it with Azure Front Door or Traffic Manager for global routing, terminate TLS at the app, keep per-environment settings sticky in slots, and let autoscale handle the peaks. That single paragraph describes a production-grade App Service design.
Worked scenario: zero-downtime release with safe data
Situation: orders.contoso.com runs on a Standard plan with a production slot connected to the live orders database. You must deploy a new version tonight with zero downtime, and under no circumstances may the staging code touch the live database during testing.
Reasoning, step by step:
- Deploy to a staging slot, not production. The staging slot gets its own hostname (
mywebapp-staging.azurewebsites.net). - Protect the data. Mark the staging slot's database connection string as a sticky slot setting pointing at the test database. Mark production's connection string sticky too, pointing at the live database. Now a swap can never cross the streams.
- Warm up and validate. Send test traffic to the staging URL; confirm the new version works against test data.
- Swap with preview. Phase one applies production settings to staging for a final smoke test under production configuration; then complete the swap. Traffic flips with no downtime.
- Rollback plan. If monitoring shows errors after the swap, swap back — the previous production version is still warm in the (now) staging slot.
Every element here maps to an exam fact: slots need Standard+, sticky settings don't swap, swap with preview adds an approval gate, and rollback is a reverse swap.
End-of-Chapter Test
1. You deploy an ARM template to resource group rg-app using Complete mode. The resource group currently contains a virtual network defined in the template and a storage account that is NOT in the template. What happens?
A) The deployment fails because Complete mode cannot delete resources B) The virtual network is updated and the storage account is deleted C) The virtual network is updated and the storage account is left untouched D) The resource group itself is deleted and recreated from the template
2. A Bicep file needs to deploy a new subnet into a virtual network that was created manually last year. You must not let Bicep manage or modify the virtual network itself. Which keyword should you use when declaring the virtual network resource?
A) if B) existing C) for D) module
3. You place two virtual machines in an availability set with 3 fault domains and 20 update domains. During planned Azure host maintenance, what protects your application from downtime?
A) The fault domains, because each VM runs on separate physical hardware B) The update domains, because only one update domain reboots at a time C) The availability zones, because each zone has independent power D) Nothing — planned maintenance always causes downtime for VMs in a set
4. You try to resize appvm01 from Standard_D2s_v5 to Standard_E4s_v5 and receive an error that the size is not available. What should you do?
A) Delete the VM and recreate it with the new size B) Stop the VM, resize it, then start it C) Deallocate the VM, resize it, then start it D) Move the VM to a different resource group and resize it there
5. You need an image that can be used to deploy 30 identical new web servers. The image must not carry the source VM's machine identity. What should you create?
A) A specialized image captured without preparation B) A generalized image after running sysprep on the source VM C) An incremental snapshot of the source VM's OS disk D) A backup vault recovery point of the source VM
6. You deploy a batch rendering job on Azure Spot VMs with the eviction policy set to Deallocate. Azure needs the capacity back. What happens?
A) The VMs keep running because batch jobs cannot be evicted B) The VMs receive a 30-second notice, then are stopped with their disks preserved C) The VMs are immediately deleted along with their disks and no notice is given D) The VMs are live-migrated to on-demand capacity automatically
7. Your company needs container images pulled from the Azure region closest to each deployment, worldwide, from a single registry. Which Azure Container Registry SKU meets this requirement?
A) Basic, with zone redundancy enabled B) Standard, with a virtual network service endpoint C) Premium, with geo-replication configured D) Any SKU, because all registries replicate globally by default
8. A development team wants to run an event-driven API in containers. It must scale to zero overnight to save cost, support traffic splitting between two revisions for canary releases, and require no Kubernetes management. Which service should you choose?
A) Azure Container Instances B) Azure Container Apps C) Azure Kubernetes Service D) Virtual machines running Docker Engine
9. An App Service web app slows down every weekday at 9 AM when users log in, then idles overnight. Which approach handles this automatically with the least waste?
A) Scale up the App Service plan from Basic to Premium each morning B) Configure autoscale rules on a Standard plan to add instances on CPU/schedule triggers C) Deploy additional instances manually every morning and remove them at night D) Move the app to the Free tier overnight and back to Standard each morning
10. Your web app has a production slot and a staging slot. Each slot must keep pointing at its own database — staging to the test database, production to the live database — even after swaps. What should you do?
A) Use swap with preview so settings are checked before completing the swap B) Mark both connection strings as deployment slot (sticky) settings C) Store the connection strings in Azure Key Vault instead of app settings D) Delete the staging slot after each swap and recreate it
11. You need HTTPS on shop.contoso.com (a subdomain) with the lowest cost and automatic renewal, and you do not need wildcard support. Which certificate option fits?
A) App Service managed certificate B) IP SSL with a self-signed certificate C) An App Service Certificate for *.contoso.com D) Uploading a PFX from an enterprise CA
12. You are designing storage for a new virtual machine that will run a high-transaction database on its data disks and needs the lowest possible disk latency. Which disk choice is valid?
A) Ultra Disk for the OS disk and Premium SSD v2 for data disks B) Ultra Disk for the data disks and Premium SSD v1 for the OS disk C) Standard HDD for the OS disk and Ultra Disk for data disks in all regions D) Premium SSD v2 for the OS disk and Standard SSD for the data disks
Answer Key
1. B — Complete mode deletes resources in the resource group that are not in the template. The VNet is updated; the storage account is deleted. The resource group itself is never deleted.
2. B — The existing keyword references a resource created outside the deployment so Bicep can use it without managing it.
3. B — Update domains protect against planned maintenance: Azure reboots one update domain at a time. Fault domains protect against unplanned hardware failure.
4. C — A stopped-but-allocated VM keeps its hardware cluster lease. Deallocate releases it, allowing Azure to place the VM on a cluster with the new size available.
5. B — A generalized image (sysprep on Windows, deprovision on Linux) strips machine identity and can be cloned freely. Specialized images retain identity and are for restoring one VM.
6. B — Spot evictions come with a 30-second notice. With the Deallocate policy, VMs stop but their disks are preserved so work can resume later.
7. C — Geo-replication is a Premium-only ACR feature: push once, pull from the nearest replicated region.
8. B — Container Apps provides KEDA-driven scaling including scale-to-zero, multiple revisions with traffic splitting, and no Kubernetes management. ACI lacks revisions/traffic splitting; AKS requires cluster management.
9. B — Autoscale (Standard tier and above) adds instances on metric or schedule triggers automatically. Scaling up changes the tier (brief restart, manual); manual instance juggling defeats the purpose.
10. B — Sticky (deployment slot) settings stay with their slot during a swap; everything else swaps. Marking both connection strings sticky keeps each environment on its own database.
11. A — The App Service managed certificate is free and auto-renewed, and it supports subdomains like shop.contoso.com. Its limits (no wildcards, no apex domains) don't apply here.
12. B — Ultra Disk cannot be an OS disk (data disks only), so A is invalid. Ultra Disk is valid for data disks where supported; Premium SSD v1 is a fine OS disk. C is wrong because Ultra Disk has limited regional availability, and D underserves the database's latency need.