Module 1 – Virtual Machines (VMs)
VM Advantages
| Advantage | Description |
|---|---|
| Flexibility | Choose the size, OS, and configuration |
| Cost-efficiency | Pay-as-you-go, predictable with Reserved Instances |
| Agility | Deploy in minutes via portal, CLI, or ARM templates |
| Reliability | Redundant infrastructure, availability SLAs |
Available OS
- Windows Server: 2012, 2016, 2019, 2022.
- Linux: Ubuntu (20.04, 22.04), RHEL, SUSE, Debian, CentOS, etc.
VM Lifecycle
| State | Resources | Billing |
|---|---|---|
| Running | CPU, memory, storage | Compute billing |
| Stopped (OS shutdown) | Reserved (static IP retained) | Still billed |
| Deallocated | Released (IP may change) | Storage only |
Tip: Use
Deallocate(not just Stop) to avoid compute charges.
Create a VM via CLI
az vm create \
--resource-group myResourceGroup \
--name MyUbuntuVM \
--image Ubuntu2204 \
--admin-username azureuser \
--authentication-type ssh \
--generate-ssh-keys \
--size Standard_D2s_v3
# Manage the VM
az vm start --resource-group myRG --name MyVM
az vm stop --resource-group myRG --name MyVM
az vm deallocate --resource-group myRG --name MyVM
az vm restart --resource-group myRG --name MyVM
ARM Template for Automating VMs
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"parameters": {
"computerName": {"type": "string"},
"adminUsername": {"type": "string"},
"adminPassword": {"type": "securestring"}
},
"resources": [
{
"type": "Microsoft.Network/virtualNetworks",
"name": "[concat(parameters('computerName'), '-vnet')]"
// ...
},
{
"type": "Microsoft.Compute/virtualMachines",
"name": "[parameters('computerName')]",
"dependsOn": ["[resourceId('Microsoft.Network/networkInterfaces', ...)]"]
// ...
}
]
}
VM Sizes
| Series | Use Case |
|---|---|
| B-series | Dev/test, lightweight workloads (burstable) |
| D-series (D2s_v3: 2vCPU, 8GB) | General applications, web, databases |
| E-series | Memory-intensive (in-memory databases) |
| F-series | Compute-intensive (simulations, batch) |
| N-series | GPU (ML, 3D rendering) |
Module 2 – Azure App Service
Characteristics
- PaaS: Azure manages servers, patches, scalability.
- Deploy code from: GitHub, Azure Repos, Bitbucket, Zip, Docker.
- Languages: .NET, .NET Core, Java, Node.js, PHP, Python, Ruby.
- Included features: HTTPS/TLS, custom domains, auto-scaling, load balancing.
- Compliance: ISO, SOC, GDPR.
App Service Plans
| Plan | SKU | Description |
|---|---|---|
| Free/Shared | F1, D1 | Dev/test, strict limits |
| Basic | B1, B2, B3 | Small apps, no autoscaling |
| Standard | S1, S2, S3 | Production, autoscaling, staging slots |
| Premium | P1v3, P2v3 | High performance, VNet, ACR |
| Isolated | I1, I2, I3 | Dedicated environment (ASE) |
Deployment from GitHub Actions
name: Deploy to Azure App Service
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Deploy to Azure Web App
uses: azure/webapps-deploy@v2
with:
app-name: 'my-app'
publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }}
package: .
Module 3 – Azure Functions (Fundamentals Summary)
Concept
- Event-driven serverless: code triggered by events.
- No servers to manage.
- Pay per execution: 1 million free invocations/month.
Common Triggers
| Trigger | Initiator |
|---|---|
| HTTP | Web requests, webhooks, APIs |
| Timer | Scheduled (cron) |
| Queue | New message in a Storage queue |
| Blob | New file in Azure Blob Storage |
| Cosmos DB | Changes in a collection |
Compute Options Comparison
| Service | Type | Control | Scalability | Use Case |
|---|---|---|---|---|
| Virtual Machines | IaaS | High | Manual + auto | Lift-and-shift, legacy apps |
| App Service | PaaS | Medium | Auto | Web apps, REST APIs |
| Azure Functions | FaaS/Serverless | Low | Automatic | Event processing, microservices |
| Container Instances | Containers | Medium | Manual | Isolated/ephemeral containers |
| AKS | Kubernetes | High | Auto | Complex container orchestration |
Key Takeaways
- VM Deallocated ≠ VM Stopped → only Deallocated stops compute billing.
- App Service = PaaS, Microsoft manages the server, you manage the app.
- Functions = serverless, triggered by events, pay-per-execution.
- Always prefer SSH keys over passwords for Linux VMs.
- ARM templates = automate infrastructure deployment (Infrastructure as Code).
Advanced Sections – Course Enrichment
Module 4 – VM Scale Sets (VMSS)
Concept and Advantages
VM Scale Sets allow deploying and managing a set of identical VMs with automatic scaling. Azure monitors the load and adjusts the number of instances without manual intervention.
| Feature | Description |
|---|---|
| Autoscaling | Automatic increase/decrease based on CPU, memory, queue metrics |
| Integrated Load Balancer | Traffic distribution across all instances |
| Coordinated updates | Zero-downtime deployments |
| Managed disks | Simplified storage management |
| Zone support | Instances spread across multiple Availability Zones |
VMSS Architecture
graph TD
LB[Azure Load Balancer / Application Gateway]
LB --> VM1[VM Instance 1]
LB --> VM2[VM Instance 2]
LB --> VM3[VM Instance 3]
LB --> VMn[VM Instance N...]
AS[Autoscale Engine] -->|Scale Out / Scale In| LB
MON[Azure Monitor - Metrics] --> AS
HP[Health Probes] --> LB
Scaling Policies
Scale-Out (increase) and Scale-In (decrease)
# Create a VMSS with autoscaling
az vmss create \
--resource-group myRG \
--name myScaleSet \
--image Ubuntu2204 \
--upgrade-policy-mode Automatic \
--admin-username azureuser \
--generate-ssh-keys \
--instance-count 2 \
--vm-sku Standard_D2s_v3
# Configure autoscaling (min 2, max 10 instances, 70% CPU threshold)
az monitor autoscale create \
--resource-group myRG \
--resource myScaleSet \
--resource-type Microsoft.Compute/virtualMachineScaleSets \
--name autoscaleProfile \
--min-count 2 \
--max-count 10 \
--count 2
# Scale-Out rule: CPU > 70% for 5 min → +2 instances
az monitor autoscale rule create \
--resource-group myRG \
--autoscale-name autoscaleProfile \
--scale out 2 \
--condition "Percentage CPU > 70 avg 5m"
# Scale-In rule: CPU < 30% for 10 min → -1 instance
az monitor autoscale rule create \
--resource-group myRG \
--autoscale-name autoscaleProfile \
--scale in 1 \
--condition "Percentage CPU < 30 avg 10m"
Upgrade Policies
| Policy | Behavior | Use Case |
|---|---|---|
| Automatic | Azure updates all instances automatically | Non-critical environments |
| Rolling | Update in batches, health check between each batch | Production with high availability |
| Manual | Update triggered manually by the operator | Full control, sensitive migrations |
# Change the upgrade policy
az vmss update \
--resource-group myRG \
--name myScaleSet \
--set upgradePolicy.mode=Rolling \
--set upgradePolicy.rollingUpgradePolicy.maxBatchInstancePercent=20 \
--set upgradePolicy.rollingUpgradePolicy.maxUnhealthyInstancePercent=20 \
--set upgradePolicy.rollingUpgradePolicy.pauseTimeBetweenBatches="PT0S"
Health Probes and Application Health Extension
# Add an HTTP health probe (port 80, path /health)
az network lb probe create \
--resource-group myRG \
--lb-name myScaleSetLB \
--name myHealthProbe \
--protocol Http \
--port 80 \
--path /health \
--interval 15 \
--threshold 2
Managed vs Unmanaged Disks
| Criteria | Managed Disks | Unmanaged Disks |
|---|---|---|
| Management | Azure manages the storage account | You manage the storage account |
| Availability | 99.999% SLA | Depends on your configuration |
| Simplicity | Recommended (default) | Deprecated for new projects |
| Snapshots | Native, simple | Manual |
| Encryption | SSE enabled by default | Configurable |
Bicep — Full VMSS Deployment
param location string = resourceGroup().location
param vmssName string = 'myScaleSet'
param instanceCount int = 2
param vmSku string = 'Standard_D2s_v3'
param adminUsername string
@secure()
param adminPassword string
resource vmss 'Microsoft.Compute/virtualMachineScaleSets@2023-03-01' = {
name: vmssName
location: location
sku: {
name: vmSku
tier: 'Standard'
capacity: instanceCount
}
properties: {
upgradePolicy: {
mode: 'Rolling'
rollingUpgradePolicy: {
maxBatchInstancePercent: 20
maxUnhealthyInstancePercent: 20
pauseTimeBetweenBatches: 'PT0S'
}
}
virtualMachineProfile: {
osProfile: {
computerNamePrefix: 'vmss-node'
adminUsername: adminUsername
adminPassword: adminPassword
}
storageProfile: {
imageReference: {
publisher: 'Canonical'
offer: '0001-com-ubuntu-server-jammy'
sku: '22_04-lts-gen2'
version: 'latest'
}
osDisk: {
createOption: 'FromImage'
managedDisk: {
storageAccountType: 'Premium_LRS'
}
}
}
networkProfile: {
networkInterfaceConfigurations: [
{
name: 'myNicConfig'
properties: {
primary: true
ipConfigurations: [
{
name: 'myIpConfig'
properties: {
subnet: {
id: resourceId('Microsoft.Network/virtualNetworks/subnets', 'myVnet', 'mySubnet')
}
}
}
]
}
}
]
}
}
}
}
Module 5 – Azure App Service (Deep Dive)
App Service Plans – Full Detail
| Plan | SKU | vCPU | RAM | Storage | Autoscaling | Slots | Indicative price/month |
|---|---|---|---|---|---|---|---|
| Free | F1 | Shared | 1 GB | 1 GB | No | 0 | Free |
| Shared | D1 | Shared | 1 GB | 1 GB | No | 0 | ~$10 |
| Basic | B1/B2/B3 | 1-4 | 1.75-7 GB | 10 GB | No | 0 | ~$13-$55 |
| Standard | S1/S2/S3 | 1-4 | 1.75-7 GB | 50 GB | Yes (5) | 5 | ~$73-$292 |
| Premium v3 | P1v3/P2v3/P3v3 | 2-8 | 8-32 GB | 250 GB | Yes (20) | 20 | ~$138-$552 |
| Isolated v2 | I1v2-I6v2 | 2-32 | 8-128 GB | 1 TB | Yes (max) | 20 | ~$302+ |
App Service Environment (ASE): deployment in your private VNet, full network isolation, requires the Isolated plan.
Deployment Slots — Blue/Green Strategy
graph LR
DEV[Dev Branch] -->|CI/CD Push| STAGING[Staging Slot\n staging.azurewebsites.net]
STAGING -->|Validation tests| SWAP{Swap to Production}
SWAP -->|Success| PROD[Production Slot\n app.azurewebsites.net]
SWAP -->|Failure| ROLLBACK[Reverse swap\n back to Staging]
PROD -->|100% traffic| USERS[Users]
# Create a staging slot
az webapp deployment slot create \
--resource-group myRG \
--name myApp \
--slot staging
# Deploy to the staging slot
az webapp deployment source config-zip \
--resource-group myRG \
--name myApp \
--slot staging \
--src ./app.zip
# Swap staging → production (zero-downtime)
az webapp deployment slot swap \
--resource-group myRG \
--name myApp \
--slot staging \
--target-slot production
# Auto-swap: automatic swap on every staging deployment
az webapp deployment slot auto-swap \
--resource-group myRG \
--name myApp \
--slot staging \
--auto-swap-slot production
Deployment Options
| Method | Description | CI/CD |
|---|---|---|
| ZIP Deploy | Compress and push via CLI/REST | Manual or scriptable |
| GitHub Actions | Automated pipeline via .github/workflows | Yes |
| Azure DevOps Pipelines | YAML pipeline in Azure Repos | Yes |
| FTP/FTPS | Direct file upload | Not recommended |
| Visual Studio Publish | Direct publish from IDE | Local development |
| Docker/ACR | Container image deployment | Yes |
| Local Git | Push to a Git repo hosted by Azure | Yes |
App Service Autoscaling
# Enable autoscaling on the App Service plan
az monitor autoscale create \
--resource-group myRG \
--resource myAppServicePlan \
--resource-type Microsoft.Web/serverfarms \
--name webAppAutoscale \
--min-count 1 \
--max-count 5 \
--count 1
# Rule: scale-out if CPU > 80%
az monitor autoscale rule create \
--resource-group myRG \
--autoscale-name webAppAutoscale \
--scale out 1 \
--condition "CpuPercentage > 80 avg 5m"
# Rule: scale-in if CPU < 20%
az monitor autoscale rule create \
--resource-group myRG \
--autoscale-name webAppAutoscale \
--scale in 1 \
--condition "CpuPercentage < 20 avg 10m"
Custom Domain + TLS
# Bind a custom domain
az webapp config hostname add \
--resource-group myRG \
--webapp-name myApp \
--hostname www.mydomain.com
# Create and bind an Azure-managed TLS certificate (free on Standard+)
az webapp config ssl bind \
--resource-group myRG \
--name myApp \
--certificate-thumbprint <THUMBPRINT> \
--ssl-type SNI
# Enforce HTTPS
az webapp update \
--resource-group myRG \
--name myApp \
--https-only true
Application Settings vs Connection Strings
| Type | Storage | Code Access | Recommended Usage |
|---|---|---|---|
| App Settings | Encrypted key/value | Environment.GetEnvironmentVariable() | General config, feature flags |
| Connection Strings | Encrypted key/value | ConfigurationManager.ConnectionStrings | DB connection strings |
| Key Vault Reference | Reference to Azure Key Vault | Transparent (same API) | Sensitive secrets (production) |
# Set App Settings
az webapp config appsettings set \
--resource-group myRG \
--name myApp \
--settings \
ENVIRONMENT=production \
API_KEY=@Microsoft.KeyVault(SecretUri=https://myKV.vault.azure.net/secrets/apikey/)
# Set a Connection String
az webapp config connection-string set \
--resource-group myRG \
--name myApp \
--connection-string-type SQLAzure \
--settings DefaultConnection="Server=tcp:myserver.database.windows.net;..."
Module 6 – Azure Container Instances (ACI)
Concept — Serverless Containers
Azure Container Instances allows running Docker containers without managing servers or orchestrators. Ideal for ephemeral tasks, burst workloads, or CI/CD pipelines.
| Feature | Detail |
|---|---|
| Startup | A few seconds (no VM provisioning) |
| Billing | Per second of execution + allocated resources |
| OS | Linux and Windows |
| Network | Public IP or VNet integration |
| Storage | Azure Files volumes, ephemeral volumes |
| Registry | Docker Hub, Azure Container Registry (ACR) |
Architecture — Container Groups
A Container Group is the highest-level resource in ACI. It can contain multiple containers sharing the same network and lifecycle (sidecar pattern).
graph TD
CG[Container Group\n IP: 40.x.x.x]
CG --> APP[Main Container\n app:latest\n Port 80\n 1 vCPU / 1.5 GB]
CG --> SIDECAR[Sidecar Container\n log-collector:latest\n Port 9090\n 0.5 vCPU / 0.5 GB]
CG --> VOL[Shared Volume\n Azure Files]
APP --> VOL
SIDECAR --> VOL
Restart Policies
| Policy | Behavior | Use Case |
|---|---|---|
| Always | Always restarts after stopping | Long-running services |
| Never | Never restarts | Batch tasks, one-time jobs |
| OnFailure | Restarts only if the container fails | Scripts with retry logic |
Deployment via Azure CLI
# Simple container deployment
az container create \
--resource-group myRG \
--name myContainer \
--image mcr.microsoft.com/azuredocs/aci-helloworld \
--cpu 1 \
--memory 1.5 \
--ports 80 \
--dns-name-label myapp-demo \
--restart-policy OnFailure \
--environment-variables \
ENV=production \
APP_VERSION=1.0
# Check status
az container show \
--resource-group myRG \
--name myContainer \
--query "{Status:instanceView.state, IP:ipAddress.ip}" \
--output table
# View logs
az container logs --resource-group myRG --name myContainer
# Delete
az container delete --resource-group myRG --name myContainer --yes
Multi-container Deployment via YAML
# container-group.yaml
apiVersion: 2021-10-01
location: eastus
name: myContainerGroup
properties:
containers:
- name: main-app
properties:
image: mcr.microsoft.com/azuredocs/aci-helloworld
resources:
requests:
cpu: 1.0
memoryInGb: 1.5
ports:
- port: 80
protocol: TCP
volumeMounts:
- name: shared-logs
mountPath: /var/log/app
- name: log-sidecar
properties:
image: busybox
command: ["sh", "-c", "tail -f /var/log/app/app.log"]
resources:
requests:
cpu: 0.5
memoryInGb: 0.5
volumeMounts:
- name: shared-logs
mountPath: /var/log/app
osType: Linux
ipAddress:
type: Public
ports:
- protocol: TCP
port: 80
restartPolicy: OnFailure
volumes:
- name: shared-logs
azureFile:
shareName: myfileshare
storageAccountName: mystorageaccount
storageAccountKey: <key>
tags: {}
type: Microsoft.ContainerInstance/containerGroups
# Deploy via YAML file
az container create \
--resource-group myRG \
--file container-group.yaml
ACI Resource Limits
| Resource | Limit per container | Limit per group |
|---|---|---|
| vCPU | 4 | 4 |
| Memory | 16 GB | 16 GB |
| Temp storage | 50 GB | 50 GB |
| GPU | 4 (K80/P100/V100) | 4 |
Module 7 – Azure Kubernetes Service (AKS)
AKS Architecture
graph TB
subgraph "Control Plane (managed by Azure)"
API[API Server]
ETCD[etcd]
SCH[Scheduler]
CM[Controller Manager]
end
subgraph "System Node Pool"
NS1[Node 1\n Standard_D4s_v3]
NS2[Node 2\n Standard_D4s_v3]
end
subgraph "Application Node Pool"
NA1[Node 3\n Standard_D8s_v3]
NA2[Node 4\n Standard_D8s_v3]
NA3[Node 5\n Standard_D8s_v3]
end
API --> NS1
API --> NS2
API --> NA1
API --> NA2
API --> NA3
INGRESS[Ingress Controller\n NGINX / App Gateway] --> NS1
HPA[HPA\n Horizontal Pod Autoscaler] --> NA1
PVC[Persistent Volume Claims\n Azure Disks / Files] --> NA1
Create an AKS Cluster
# Create an AKS cluster with 2 node pools
az aks create \
--resource-group myRG \
--name myAKSCluster \
--node-count 2 \
--node-vm-size Standard_D4s_v3 \
--network-plugin azure \
--enable-managed-identity \
--enable-addons monitoring \
--generate-ssh-keys \
--kubernetes-version 1.28.0
# Get kubectl credentials
az aks get-credentials \
--resource-group myRG \
--name myAKSCluster
# Add an application node pool
az aks nodepool add \
--resource-group myRG \
--cluster-name myAKSCluster \
--name apppool \
--node-count 3 \
--node-vm-size Standard_D8s_v3 \
--mode User
Fundamental Kubernetes Objects
| Object | Role |
|---|---|
| Pod | Minimum deployment unit, 1+ containers |
| Deployment | Manages pod lifecycle, rolling updates |
| Service | Stable network exposure of pods (ClusterIP, NodePort, LoadBalancer) |
| Ingress | External HTTP/HTTPS routing to services |
| ConfigMap | Non-secret configuration |
| Secret | Sensitive data (credentials, certs) |
| PersistentVolumeClaim | Request for persistent storage |
| HorizontalPodAutoscaler | Metrics-based autoscaling |
| Namespace | Logical isolation of resources |
YAML Manifest Files
# deployment.yaml — Web application
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
namespace: production
labels:
app: my-app
spec:
replicas: 3
selector:
matchLabels:
app: my-app
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app
image: myacr.azurecr.io/my-app:v1.2.0
ports:
- containerPort: 8080
resources:
requests:
cpu: "250m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
env:
- name: ASPNETCORE_ENVIRONMENT
value: "Production"
- name: ConnectionStrings__DefaultConnection
valueFrom:
secretKeyRef:
name: app-secrets
key: db-connection
livenessProbe:
httpGet:
path: /health/live
port: 8080
initialDelaySeconds: 10
periodSeconds: 15
readinessProbe:
httpGet:
path: /health/ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
---
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: my-app-svc
namespace: production
spec:
selector:
app: my-app
ports:
- port: 80
targetPort: 8080
type: ClusterIP
---
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app-ingress
namespace: production
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: nginx
tls:
- hosts:
- app.mydomain.com
secretName: app-tls-cert
rules:
- host: app.mydomain.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app-svc
port:
number: 80
HPA — Horizontal Pod Autoscaler
# hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-app-hpa
namespace: production
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 3
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
Essential kubectl Commands
# Context and cluster
kubectl config get-contexts
kubectl config use-context myAKSCluster
# Pods and deployments
kubectl get pods -n production -o wide
kubectl describe pod my-app-xxx -n production
kubectl logs my-app-xxx -n production --tail=100 -f
kubectl exec -it my-app-xxx -n production -- /bin/bash
# Deployment and updates
kubectl apply -f deployment.yaml
kubectl rollout status deployment/my-app -n production
kubectl rollout history deployment/my-app -n production
kubectl rollout undo deployment/my-app -n production # Rollback
# Manual scaling
kubectl scale deployment my-app --replicas=5 -n production
# Services and ingress
kubectl get svc -n production
kubectl get ingress -n production
# Namespaces
kubectl create namespace production
kubectl get all -n production
# Resources
kubectl top pods -n production
kubectl top nodes
# PVC
kubectl get pvc -n production
kubectl describe pvc my-pvc -n production
AKS Network: Azure CNI vs Kubenet
| Criteria | Azure CNI | Kubenet |
|---|---|---|
| IP assignment | Each pod gets a VNet IP | NAT — pods share the node IP |
| Performance | High (direct VNet connection) | Slightly lower (NAT) |
| IP consumption | High (plan address space) | Low |
| Azure services | Native integration (Private Link, etc.) | Limitations for some services |
| Use case | Production, complex VNet integration | Simple environments, dev |
PVC — Persistent Storage
# pvc.yaml — Azure Premium disk
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
namespace: production
spec:
accessModes:
- ReadWriteOnce
storageClassName: managed-premium
resources:
requests:
storage: 32Gi
Module 8 – Azure Functions (Deep Dive)
Consumption and Hosting Plans
| Plan | Billing | Cold Start | Duration Limit | Scalability |
|---|---|---|---|---|
| Consumption | Per execution + GB-s | Yes (~1-3s) | 10 min | Auto (0→∞) |
| Premium | Always-warm plan | No | Unlimited | Auto + VNet |
| Dedicated (App Service) | App Service plan | No | Unlimited | Manual or auto |
| Container Apps | Per vCPU-s + memory | Yes (configurable) | Unlimited | Auto |
Triggers and Bindings
graph LR
T1[HTTP Request] -->|Trigger| FUNC[Azure Function]
T2[Timer\n CRON] -->|Trigger| FUNC
T3[Azure Queue\n Storage] -->|Trigger| FUNC
T4[Blob Storage\n New file] -->|Trigger| FUNC
T5[Cosmos DB\n Change Feed] -->|Trigger| FUNC
T6[Event Grid\n Event Hub] -->|Trigger| FUNC
FUNC -->|Output Binding| OUT1[Azure Queue]
FUNC -->|Output Binding| OUT2[Cosmos DB]
FUNC -->|Output Binding| OUT3[SendGrid Email]
FUNC -->|Output Binding| OUT4[SignalR]
Code Examples
// HTTP Trigger — Simple REST API
[FunctionName("GetWeather")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = "weather/{city}")]
HttpRequest req,
string city,
ILogger log)
{
log.LogInformation($"Weather request for: {city}");
var result = await weatherService.GetWeatherAsync(city);
return new OkObjectResult(result);
}
// Timer Trigger — Daily report at 8:00 AM UTC
[FunctionName("DailyReport")]
public static async Task Run(
[TimerTrigger("0 0 8 * * *")] TimerInfo timer,
[CosmosDB("myDB", "myCollection", Connection = "CosmosDBConnection")]
IAsyncCollector<ReportDocument> reports,
ILogger log)
{
var report = await generateReportAsync();
await reports.AddAsync(report);
log.LogInformation("Daily report generated and saved.");
}
// Queue Trigger + Blob Output Binding
[FunctionName("ProcessImage")]
public static async Task Run(
[QueueTrigger("images-to-process", Connection = "StorageConnection")]
string messageJson,
[Blob("processed-images/{rand-guid}.jpg", FileAccess.Write, Connection = "StorageConnection")]
Stream outputBlob,
ILogger log)
{
var message = JsonSerializer.Deserialize<ImageMessage>(messageJson);
var processedImage = await resizeImageAsync(message.BlobUrl);
await processedImage.CopyToAsync(outputBlob);
}
Durable Functions — Workflow Orchestration
// Orchestrator — E-commerce order
[FunctionName("ProcessOrder")]
public static async Task<string> RunOrchestrator(
[OrchestrationTrigger] IDurableOrchestrationContext context)
{
var order = context.GetInput<Order>();
// Sequential execution
await context.CallActivityAsync("ValidatePayment", order.PaymentId);
await context.CallActivityAsync("ReserveStock", order.Items);
// Parallel execution
var parallelTasks = new List<Task>
{
context.CallActivityAsync("SendConfirmationEmail", order.Email),
context.CallActivityAsync("NotifyWarehouse", order.Items),
context.CallActivityAsync("UpdateCRM", order.CustomerId)
};
await Task.WhenAll(parallelTasks);
return $"Order {order.Id} processed successfully";
}
// Activity
[FunctionName("ValidatePayment")]
public static async Task<bool> ValidatePayment(
[ActivityTrigger] string paymentId,
ILogger log)
{
log.LogInformation($"Validating payment: {paymentId}");
return await paymentService.ValidateAsync(paymentId);
}
Deploy Functions via Azure CLI
# Create the Function App (Consumption plan)
az functionapp create \
--resource-group myRG \
--consumption-plan-location eastus \
--runtime dotnet-isolated \
--runtime-version 8 \
--functions-version 4 \
--name myFunctionApp \
--storage-account mystorageaccount \
--os-type Linux
# Deploy the code
func azure functionapp publish myFunctionApp
# Configure app settings
az functionapp config appsettings set \
--resource-group myRG \
--name myFunctionApp \
--settings \
CosmosDBConnection="AccountEndpoint=https://..." \
StorageConnection="DefaultEndpointsProtocol=https;..."
# Enable Application Insights
az monitor app-insights component create \
--resource-group myRG \
--app myFunctionApp-insights \
--location eastus \
--kind web
Module 9 – Azure Service Fabric
Microservices Platform
Azure Service Fabric is a distributed platform for deploying and managing scalable and reliable microservices. Unlike AKS (containers), Service Fabric can host native processes or containers.
graph TD
SF[Service Fabric Cluster\n 5-7 Primary Nodes + Secondary Nodes]
SF --> APP1[Application\n Product Catalog]
SF --> APP2[Application\n Order Management]
APP1 --> SS1[Stateless Service\n Frontend API]
APP1 --> ST1[Stateful Service\n Product Cache\n Reliable Collections]
APP2 --> SS2[Stateless Service\n Orders API]
APP2 --> ST2[Stateful Service\n Order State\n Reliable Dictionary]
APP2 --> ACT[Reliable Actors\n Customer Cart Session]
Stateless vs Stateful Services
| Criteria | Stateless | Stateful |
|---|---|---|
| State | No persistent local state | Local persistent state via Reliable Collections |
| Scalability | Trivial — add instances | Automatic partitioning (sharding) |
| Examples | Web APIs, stateless workers | Shopping cart, distributed cache, counters |
| Reliability | Restart = state lost | Automatic replication on 3+ replicas |
| Use case | Calculations, gateways, orchestrators | Frequently accessed data, low latency |
Reliable Collections
// Stateful Service with Reliable Dictionary
public class CartManagement : StatefulService
{
protected override async Task RunAsync(CancellationToken cancellationToken)
{
// Get (or create) a replicated reliable dictionary
var carts = await StateManager
.GetOrAddAsync<IReliableDictionary<string, Cart>>("carts");
while (!cancellationToken.IsCancellationRequested)
{
using var tx = StateManager.CreateTransaction();
// Read
var result = await carts.TryGetValueAsync(tx, "customer123");
var cart = result.HasValue ? result.Value : new Cart();
// Modify
cart.AddItem(new Item("PROD-001", 2));
// Transactional write (automatically replicated)
await carts.SetAsync(tx, "customer123", cart);
await tx.CommitAsync();
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
}
}
}
When to Choose Service Fabric vs AKS?
| Criteria | Service Fabric | AKS |
|---|---|---|
| Service type | Native stateful | Containers (stateless recommended) |
| Learning curve | High (specific SDK) | Moderate (standard Kubernetes) |
| Portability | Limited (Microsoft proprietary) | High (universal Kubernetes) |
| Distributed state | Native and optimized | Via volumes / external databases |
| Ecosystem | Microsoft-centric | Universal cloud-native ecosystem |
| Recommendation | Legacy Fabric apps or very stateful services | New projects, modern microservices |
Module 10 – Comparisons and Architectural Choices
Complete Decision Table
| Criteria | VM | VMSS | App Service | ACI | AKS | Functions |
|---|---|---|---|---|---|---|
| OS Control | Full | Full | None | None | Partial | None |
| Infrastructure management | You | You (auto) | Azure | Azure | Shared | Azure |
| Startup | Minutes | Minutes | Seconds | Seconds | Seconds | ms (warm) |
| Autoscaling | Manual | Automatic | Automatic | No | HPA auto | Automatic |
| Billing | Per hour (deallocated=0) | Per hour × instances | Per plan/hour | Per second | Per node/hour | Per execution |
| Containers | Via Docker manual | Not native | Yes (via Docker) | Yes (native) | Yes (orchestrated) | Yes (Premium) |
| State | With disks | With disks | Stateless recommended | Ephemeral | Via PVC | Stateless |
| VNet | Native | Native | Premium/Isolated | Optional | Native | Premium |
| Use case | IaaS/Legacy | Web scale | Web/API | Short tasks | Microservices | Event-driven |
Decision Tree — Choosing a Compute Service
flowchart TD
START([New Azure workload]) --> Q1{Need full\nOS control?}
Q1 -->|Yes| Q2{Automatic\nscalability required?}
Q1 -->|No| Q3{Container-based\napplication?}
Q2 -->|Yes| VMSS[VM Scale Sets\nBuilt-in autoscaling]
Q2 -->|No| VM[Virtual Machine\nFull IaaS control]
Q3 -->|Yes| Q4{Complex\norchestration required?}
Q3 -->|No| Q5{Web application\nor REST API?}
Q4 -->|Yes| AKS[Azure Kubernetes Service\nOrchestrated microservices]
Q4 -->|No| Q6{Short or\nephemeral task?}
Q6 -->|Yes| ACI[Azure Container Instances\nServerless containers]
Q6 -->|No| AKS
Q5 -->|Yes| Q7{Need complete\nnetwork isolation?}
Q5 -->|No| Q8{Event-driven logic\nor short processing?}
Q7 -->|Yes| ASE[App Service\nEnvironment - Isolated]
Q7 -->|No| APPSVC[Azure App Service\nPaaS web/API]
Q8 -->|Yes| FUNC[Azure Functions\nServerless FaaS]
Q8 -->|No| APPSVC
Cost Comparison (East US region estimates)
| Service | Example config | Estimated cost/month |
|---|---|---|
| VM | Standard_D2s_v3 (2vCPU, 8GB) Linux | ~$70 |
| VMSS | 3× Standard_D2s_v3 | ~$210 |
| App Service | Standard S2 (2vCPU, 3.5GB) | ~$146 |
| App Service | Premium P1v3 (2vCPU, 8GB) | ~$138 |
| ACI | 1 vCPU, 1.5GB, 730h | ~$43 |
| AKS | 3× Standard_D4s_v3 nodes | ~$420 (nodes only) |
| Functions | 1M executions, 400K GB-s | Free (within quota) |
| Functions | 10M executions, 5M GB-s | ~$4 |
These prices are estimates. Use the Azure Pricing Calculator (calculator.azure.com) for accurate estimates.
Module 11 – High Availability and Resilience
Availability Sets vs Availability Zones
graph TD
subgraph "Availability Set — same Datacenter"
FD1[Fault Domain 1\nServer Rack A\nPower supply A]
FD2[Fault Domain 2\nServer Rack B\nPower supply B]
FD3[Fault Domain 3\nServer Rack C\nPower supply C]
UD1[Update Domain 1\nVM1 + VM4]
UD2[Update Domain 2\nVM2 + VM5]
UD3[Update Domain 3\nVM3]
end
subgraph "Availability Zones — Separate Datacenters"
AZ1[Zone 1\nDatacenter A]
AZ2[Zone 2\nDatacenter B]
AZ3[Zone 3\nDatacenter C]
end
HA Comparison Table
| Mechanism | Protects Against | SLA | Granularity |
|---|---|---|---|
| Availability Set | Hardware failures, planned updates | 99.95% | VMs in same datacenter |
| Availability Zones | Complete datacenter failure | 99.99% | VMs across 3 separate datacenters |
| Azure Site Recovery | Complete regional disaster | Depends on RPO/RTO config | Cross-region replication |
| Geo-Redundant Storage | Loss of an Azure region | 99.9999999999999% durability | Data replicated to 2nd region |
Configuring High Availability
# Create an Availability Set
az vm availability-set create \
--resource-group myRG \
--name myAvailabilitySet \
--platform-fault-domain-count 3 \
--platform-update-domain-count 5
# Deploy 3 VMs in the Availability Set
for i in 1 2 3; do
az vm create \
--resource-group myRG \
--name "myVM-$i" \
--availability-set myAvailabilitySet \
--image Ubuntu2204 \
--admin-username azureuser \
--generate-ssh-keys
done
# Deploy VMs across Availability Zones
az vm create \
--resource-group myRG \
--name myVM-Zone1 \
--zone 1 \
--image Ubuntu2204 \
--admin-username azureuser \
--generate-ssh-keys
az vm create \
--resource-group myRG \
--name myVM-Zone2 \
--zone 2 \
--image Ubuntu2204 \
--admin-username azureuser \
--generate-ssh-keys
Azure Site Recovery (ASR)
Azure Site Recovery ensures business continuity by replicating workloads to a secondary region.
| Parameter | Description |
|---|---|
| RPO (Recovery Point Objective) | Maximum tolerated data loss (e.g. 15 min) |
| RTO (Recovery Time Objective) | Maximum tolerated recovery time (e.g. 1h) |
| Failover | Switch to secondary region |
| Failback | Return to primary region |
| Test Failover | Simulate DR without production impact |
# Enable ASR replication for a VM (via Recovery Services Vault)
az backup protection enable-for-vm \
--resource-group myRG \
--vault-name myRecoveryVault \
--vm myProductionVM \
--policy-name DefaultPolicy
Geo-Redundancy of Managed Services
| Service | HA Option | Detail |
|---|---|---|
| Azure SQL Database | Geo-Replication, Failover Groups | Read replica in secondary region |
| Azure Storage | GRS / GZRS | 6 copies (3 local + 3 paired region) |
| Cosmos DB | Multi-region writes | Simultaneous writes to N regions |
| App Service | Traffic Manager + multi-region deployment | Geographic routing |
| AKS | Multiple clusters + Azure Front Door | Multi-region resilience |
Module 12 – Costs and Optimization
Cost Optimization Strategies
graph LR
COST[Azure Cost\nOptimization]
COST --> RI[Reserved Instances\n-40% to -72%]
COST --> SPOT[Spot VMs\n-60% to -90%]
COST --> HB[Azure Hybrid\nBenefit\nExisting licenses]
COST --> RS[Rightsizing\nAdapted size]
COST --> AS[Auto-Shutdown\nDev environments]
COST --> DEV[Dev/Test\nPricing]
Reserved Instances
| Duration | Savings (vs pay-as-you-go) | Flexibility |
|---|---|---|
| 1 year | ~40% | Size/region change possible |
| 3 years | ~60-72% | Less flexible |
| Single payment | Maximum savings | No refund flexibility |
# View reservation recommendations (Azure CLI)
az reservations reservation-order list \
--output table
# Calculate potential savings
az consumption reservation recommendation list \
--look-back-period Last7Days \
--scope "/subscriptions/SUBSCRIPTION_ID" \
--reserved-resource-type VirtualMachines
Spot VMs — Interruption-tolerant Workloads
Use cases: Batch, CI/CD workers, ML training, simulations.
# Create a Spot VM
az vm create \
--resource-group myRG \
--name mySpotVM \
--image Ubuntu2204 \
--priority Spot \
--eviction-policy Deallocate \
--max-price 0.10 \
--admin-username azureuser \
--generate-ssh-keys
# Spot in a VMSS (recommended for eviction tolerance)
az vmss create \
--resource-group myRG \
--name mySpotScaleSet \
--image Ubuntu2204 \
--priority Spot \
--eviction-policy Delete \
--max-price -1 \
--instance-count 5 \
--admin-username azureuser \
--generate-ssh-keys
Azure Hybrid Benefit
Allows using your on-premises Windows Server or SQL Server licenses (with Software Assurance) on Azure.
| Scenario | Savings |
|---|---|
| Windows Server VM | ~40% on OS license cost |
| SQL Server VM | Up to 55% |
| SQL Managed Instance | Up to 55% |
| AKS (Windows nodes) | Windows license included |
# Enable Azure Hybrid Benefit on an existing Windows VM
az vm update \
--resource-group myRG \
--name myWindowsVM \
--license-type Windows_Server
# During creation
az vm create \
--resource-group myRG \
--name myWindowsVM \
--image Win2022Datacenter \
--license-type Windows_Server \
--admin-username azureuser \
--admin-password 'P@ssw0rd123!'
Auto-Shutdown — Dev/Test Environments
# Configure auto-shutdown at 6:00 PM (local time)
az vm auto-shutdown \
--resource-group myRG \
--name myDevVM \
--time 1800 \
--email devops@mycompany.com
# PowerShell — Auto-shutdown via script for all VMs in a RG
$rg = "myDevRG"
$shutdownTime = "1800"
$timezone = "Eastern Standard Time"
Get-AzVM -ResourceGroupName $rg | ForEach-Object {
$vmId = $_.Id
$scheduleName = "shutdown-computevm-$($_.Name)"
New-AzResource `
-ResourceId "/subscriptions/$((Get-AzContext).Subscription.Id)/resourceGroups/$rg/providers/microsoft.devtestlab/schedules/$scheduleName" `
-Properties @{
status = "Enabled"
taskType = "ComputeVmShutdownTask"
dailyRecurrence = @{ time = $shutdownTime }
timeZoneId = $timezone
targetResourceId = $vmId
} `
-Force
}
Rightsizing — Identifying Under-utilized VMs
# List VMs and their CPU metrics (last 7 days)
az monitor metrics list \
--resource "/subscriptions/SUBSCRIPTION_ID/resourceGroups/myRG/providers/Microsoft.Compute/virtualMachines/myVM" \
--metric "Percentage CPU" \
--interval PT1H \
--start-time $(date -u -d '7 days ago' +%Y-%m-%dT%H:%M:%SZ) \
--end-time $(date -u +%Y-%m-%dT%H:%M:%SZ) \
--aggregation Average \
--output table
Azure Advisor — Automatic Recommendations
Azure Advisor analyzes your resources and offers recommendations in 5 categories:
| Category | Example Recommendations |
|---|---|
| Cost | Resize under-utilized VMs, delete orphaned disks |
| High availability | Add Availability Zones, configure backups |
| Security | Enable MFA, patch VMs, enable Defender |
| Performance | Switch to Premium disks, use CDN |
| Operational excellence | Update deprecated APIs, use tags |
# View Advisor recommendations via CLI
az advisor recommendation list \
--category Cost \
--output table
# VM-specific recommendations
az advisor recommendation list \
--category Cost \
--query "[?impactedField=='Microsoft.Compute/virtualMachines']" \
--output table
Module 13 – Review Questions (AZ-900 Exam)
10 Exam-Style Questions with Answers
Question 1 You have an Azure VM in the Stopped state (shut down from the OS). Which statement is correct?
- A) Compute billing has stopped
- B) The VM is still billed for compute because resources are allocated
- C) The VM loses its public IP address
- D) Disks are no longer billed
Answer: B A VM in the Stopped state (OS shutdown) retains its allocated resources (CPU, RAM, IP) and continues to be billed. Only the Deallocated state (
az vm deallocate) releases resources and stops compute billing. Disks remain billed in both cases.
Question 2 Your team is developing a .NET 8 web application without wanting to manage servers or OS patches. Which Azure solution is the best fit?
- A) Azure Virtual Machines with IIS
- B) Azure Kubernetes Service
- C) Azure App Service
- D) Azure Container Instances
Answer: C Azure App Service is a PaaS service that allows deploying web applications without managing the underlying infrastructure. Azure manages servers, OS patches, scaling and availability.
Question 3 You need to run a Docker container one-time to process an uploaded CSV file, then stop. What is the most appropriate and cost-effective solution?
- A) Azure Kubernetes Service with a Job
- B) Azure Container Instances with
restartPolicy: Never - C) Azure Virtual Machine with Docker installed
- D) Azure App Service with container
Answer: B ACI with
restartPolicy: Neveris ideal for ephemeral tasks. It starts in seconds, runs the task, stops, and billing stops per second. AKS would be oversized for a one-time task.
Question 4 Which Azure App Service feature allows you to test a new version of your application in production before making it available to all users, with the possibility of immediate rollback?
- A) Azure Traffic Manager
- B) Deployment Slots with Swap
- C) Azure Front Door
- D) Availability Zones
Answer: B Deployment Slots allow deploying to a staging slot and performing a swap to production without downtime. If an issue occurs, a reverse swap immediately restores the previous version.
Question 5 Your application generates unpredictable traffic spikes. You want Azure to automatically increase the number of VM instances based on CPU load. Which Azure resource do you use?
- A) Azure Load Balancer alone
- B) VM Scale Sets with autoscaling rules
- C) Virtual Machines with Availability Set
- D) Azure Application Gateway alone
Answer: B VM Scale Sets combined with Azure Monitor autoscaling rules allow automatically increasing or decreasing the number of instances based on metrics (CPU, memory, queue length, etc.).
Question 6 In Azure Functions, what is a binding?
- A) The network configuration of a function
- B) A declarative connection to data resources (input or output) without writing infrastructure code
- C) The function’s hosting plan
- D) An authentication mechanism
Answer: B A binding is a declarative connection in
function.jsonor via C# attributes. It can be an input (read from Cosmos DB, Blob Storage) or an output (write to a queue, send an email). The developer writes the business logic; Azure handles the connection.
Question 7 You are deploying an application on 3 VMs in Azure. You want to protect your application against hardware failures and Azure-planned updates. Which configuration do you use?
- A) 3 VMs in the same Resource Group
- B) 3 VMs in an Availability Set (3 Fault Domains, 3 Update Domains)
- C) 3 VMs in the same region
- D) 3 VMs with Azure Backup enabled
Answer: B An Availability Set distributes VMs across different Fault Domains (separate physical racks with independent power supplies) and Update Domains (groups updated separately). This ensures that a hardware failure or planned update doesn’t affect all your VMs simultaneously, offering a 99.95% SLA.
Question 8 Your company has active Windows Server licenses with Software Assurance. How do you reduce the cost of Windows Azure VMs?
- A) Use Spot VMs
- B) Enable Azure Hybrid Benefit
- C) Switch to the Free plan
- D) Use Reserved Instances only
Answer: B Azure Hybrid Benefit allows using your existing Windows Server or SQL Server licenses (with Software Assurance) to cover the OS license cost on Azure, reducing costs by up to 40% for Windows Server and 55% for SQL Server.
Question 9 What is the difference between Azure Container Instances (ACI) and Azure Kubernetes Service (AKS)?
- A) ACI does not support Linux containers
- B) ACI is serverless for isolated/simple containers; AKS orchestrates microservices at scale with advanced features (HPA, rolling deployments, networking, etc.)
- C) AKS is free, ACI is paid
- D) ACI supports more containers per group than AKS per namespace
Answer: B ACI is ideal for simple, ephemeral or isolated containers — without an orchestrator. AKS is a full Kubernetes orchestrator suited for complex microservices architectures with autoscaling, advanced traffic management, namespaces, and network integration.
Question 10 You have an Azure VM whose CPU load is consistently below 5%. Azure Advisor flags this VM. What action is recommended?
- A) Delete the VM immediately
- B) Migrate to a smaller VM size (rightsizing) to reduce costs
- C) Enable autoscaling on the VM
- D) Move the VM to another region
Answer: B Azure Advisor identifies under-utilized resources and recommends rightsizing — moving to a smaller VM size (e.g. from Standard_D4s_v3 to Standard_D2s_v3) to align costs with actual usage. This is one of the most effective cost optimization methods.
Final Recap — Visual Summary
mindmap
root((Azure Compute))
IaaS
Virtual Machines
Sizes B D E F N
Lifecycle Running Stopped Deallocated
Availability Sets & Zones
VM Scale Sets
Autoscaling
Rolling Automatic Manual
Health Probes
PaaS
App Service
Plans Free Basic Standard Premium Isolated
Deployment Slots Swap
ASE for VNet isolation
Azure Functions
Consumption Premium Dedicated
Triggers HTTP Timer Queue Blob CosmosDB
Durable Functions
Containers
ACI
Serverless containers
Container Groups
Sidecar pattern
AKS
Control Plane managed by Azure
Node Pools
kubectl HPA PVC Ingress
Azure CNI vs Kubenet
Microservices
Service Fabric
Stateless vs Stateful
Reliable Collections
Optimization
Reserved Instances 1 yr 3 yr
Spot VMs -60 to -90%
Azure Hybrid Benefit
Rightsizing via Advisor
Auto-shutdown dev
Enriched document — Azure Fundamentals Compute — All sections covered for the AZ-900 exam and beyond.
Search Terms
azure · fundamentals · compute · core · infrastructure · microsoft · service · deployment · aks · app · functions · via · vms · architecture · availability · cli · comparison · concept · plans · policies · vmss · aci · advantages · application