Available for day contractsFrom 21st September I have availability for day and half day contracts. Please contact for more information.

Contact →
mikepreston.org

Azure

Comprehensive reference for Microsoft Azure cloud services, CLI operations, and resource management.

Azure

Comprehensive reference for Microsoft Azure cloud services, CLI operations, and resource management.

Overview

Microsoft Azure is a cloud computing platform offering infrastructure, platform, and software services. It provides compute, storage, networking, databases, AI, and DevOps tools through a global network of data centres. Azure integrates tightly with Microsoft products and supports hybrid cloud scenarios.

Core ServicesAzure Resource HierarchyManagement GroupsSubscriptionsResource GroupsResourcesComputeStorageNetworkingIdentityVMsAKSApp ServiceFunctionsBlobFilesQueueTableVNetNSGLoad BalancerEntra IDRBACCore ServicesAzure Resource HierarchyManagement GroupsSubscriptionsResource GroupsResourcesComputeStorageNetworkingIdentityVMsAKSApp ServiceFunctionsBlobFilesQueueTableVNetNSGLoad BalancerEntra IDRBAC

Azure CLI Essentials

The Azure CLI (az) is the primary command-line tool for managing Azure resources.

Key Concepts

  • Subscriptions: Billing and access boundary for Azure resources
  • Resource Groups: Logical containers for grouping related resources
  • Regions: Geographic locations for resource deployment
  • Tags: Key-value pairs for resource organisation and cost tracking

Installation and Authentication

# Install Azure CLI (Ubuntu/Debian)
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash

# Install Azure CLI (macOS)
brew install azure-cli

# Login interactively
az login

# Login with service principal
az login --service-principal -u <app-id> -p <password> --tenant <tenant-id>

# Login with managed identity (from Azure VM)
az login --identity

# List accounts
az account list --output table

# Set active subscription
az account set --subscription "Subscription Name"
# or by ID
az account set --subscription xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

# Show current subscription
az account show

Resource Group Management

# Create resource group
az group create --name myResourceGroup --location uksouth

# List resource groups
az group list --output table

# Show resource group details
az group show --name myResourceGroup

# List resources in a group
az resource list --resource-group myResourceGroup --output table

# Delete resource group (and all resources within)
az group delete --name myResourceGroup --yes --no-wait

# Export resource group as ARM template
az group export --name myResourceGroup > template.json

Configuration and Output

# Configure default location
az configure --defaults location=uksouth

# Configure default resource group
az configure --defaults group=myResourceGroup

# Output formats
az vm list --output table    # Tabular format
az vm list --output json     # JSON format
az vm list --output yaml     # YAML format
az vm list --output tsv      # Tab-separated values

# Query with JMESPath
az vm list --query "[].{Name:name, RG:resourceGroup}" --output table

# Get specific property
az vm show --name myVM --resource-group myRG --query "hardwareProfile.vmSize" --output tsv

Virtual Machines

Azure Virtual Machines provide on-demand, scalable computing resources.

VM ImageVirtual MachineOS DiskData DisksNICVNet/SubnetPublic IPNSGVM ImageVirtual MachineOS DiskData DisksNICVNet/SubnetPublic IPNSG

Key Concepts

  • VM Sizes: Define CPU, memory, storage, and networking capacity
  • Images: Base OS and software configuration (marketplace or custom)
  • Availability Sets: Ensure VMs are distributed across fault and update domains
  • Scale Sets: Automatically scale identical VMs based on demand

Creating Virtual Machines

# Create a basic VM
az vm create \
    --resource-group myResourceGroup \
    --name myVM \
    --image Ubuntu2204 \
    --admin-username azureuser \
    --generate-ssh-keys \
    --size Standard_B2s

# Create VM with specific settings
az vm create \
    --resource-group myResourceGroup \
    --name myVM \
    --image Win2022Datacenter \
    --admin-username azureuser \
    --admin-password 'SecureP@ssw0rd!' \
    --size Standard_D2s_v3 \
    --public-ip-sku Standard \
    --vnet-name myVNet \
    --subnet mySubnet \
    --nsg myNSG

# List available VM sizes in a region
az vm list-sizes --location uksouth --output table

# List available images
az vm image list --output table
az vm image list --offer Ubuntu --all --output table

# Create VM from custom image
az vm create \
    --resource-group myResourceGroup \
    --name myVM \
    --image /subscriptions/{sub-id}/resourceGroups/{rg}/providers/Microsoft.Compute/images/{image-name} \
    --admin-username azureuser \
    --generate-ssh-keys

Managing Virtual Machines

# List VMs
az vm list --output table
az vm list --resource-group myResourceGroup --output table

# Show VM details
az vm show --resource-group myResourceGroup --name myVM

# Start/Stop/Restart VM
az vm start --resource-group myResourceGroup --name myVM
az vm stop --resource-group myResourceGroup --name myVM
az vm restart --resource-group myResourceGroup --name myVM

# Deallocate VM (stop billing for compute)
az vm deallocate --resource-group myResourceGroup --name myVM

# Resize VM
az vm resize --resource-group myResourceGroup --name myVM --size Standard_D4s_v3

# Delete VM
az vm delete --resource-group myResourceGroup --name myVM --yes

# Get public IP address
az vm show --resource-group myResourceGroup --name myVM \
    --show-details --query publicIps --output tsv

Connecting to VMs

# SSH to Linux VM
ssh azureuser@<public-ip>

# SSH using Azure CLI (with Entra ID authentication; requires the ssh extension)
az ssh vm --resource-group myResourceGroup --name myVM

# RDP to Windows VM
# Use Remote Desktop client with public IP and credentials

# Run command on VM
az vm run-command invoke \
    --resource-group myResourceGroup \
    --name myVM \
    --command-id RunShellScript \
    --scripts "apt-get update && apt-get install -y nginx"

# For Windows
az vm run-command invoke \
    --resource-group myResourceGroup \
    --name myVM \
    --command-id RunPowerShellScript \
    --scripts "Install-WindowsFeature -Name Web-Server"

Virtual Machine Scale Sets

# Create a scale set
az vmss create \
    --resource-group myResourceGroup \
    --name myScaleSet \
    --image Ubuntu2204 \
    --upgrade-policy-mode automatic \
    --admin-username azureuser \
    --generate-ssh-keys \
    --instance-count 2 \
    --vm-sku Standard_B2s

# List scale sets
az vmss list --output table

# Show scale set instances
az vmss list-instances \
    --resource-group myResourceGroup \
    --name myScaleSet \
    --output table

# Scale manually
az vmss scale \
    --resource-group myResourceGroup \
    --name myScaleSet \
    --new-capacity 5

# Configure autoscale
az monitor autoscale create \
    --resource-group myResourceGroup \
    --resource myScaleSet \
    --resource-type Microsoft.Compute/virtualMachineScaleSets \
    --name autoscale-config \
    --min-count 2 \
    --max-count 10 \
    --count 2

# Add autoscale rule (scale out on CPU > 70%)
az monitor autoscale rule create \
    --resource-group myResourceGroup \
    --autoscale-name autoscale-config \
    --condition "Percentage CPU > 70 avg 5m" \
    --scale out 1

# Update instances
az vmss update-instances \
    --resource-group myResourceGroup \
    --name myScaleSet \
    --instance-ids "*"

# Delete scale set
az vmss delete --resource-group myResourceGroup --name myScaleSet

Storage Accounts

Azure Storage provides scalable, durable cloud storage for various data types.

Storage AccountStorage AccountBlob StorageFile StorageQueue StorageTable StorageContainersBlock BlobsAppend BlobsPage BlobsFile SharesDirectoriesFilesStorage AccountStorage AccountBlob StorageFile StorageQueue StorageTable StorageContainersBlock BlobsAppend BlobsPage BlobsFile SharesDirectoriesFiles

Key Concepts

  • Blob Storage: Object storage for unstructured data (files, images, backups)
  • File Storage: Managed file shares accessible via SMB/NFS
  • Queue Storage: Message queuing for application communication
  • Table Storage: NoSQL key-value store for structured data
  • Access Tiers: Hot, Cool, Cold, and Archive for cost optimisation

Creating Storage Accounts

# Create storage account
az storage account create \
    --name mystorageaccount \
    --resource-group myResourceGroup \
    --location uksouth \
    --sku Standard_LRS \
    --kind StorageV2

# Create with redundancy options
az storage account create \
    --name mystorageaccount \
    --resource-group myResourceGroup \
    --location uksouth \
    --sku Standard_GRS \
    --kind StorageV2 \
    --access-tier Hot

# List storage accounts
az storage account list --output table

# Get storage account keys
az storage account keys list \
    --account-name mystorageaccount \
    --resource-group myResourceGroup \
    --output table

# Get connection string
az storage account show-connection-string \
    --name mystorageaccount \
    --resource-group myResourceGroup \
    --output tsv

Blob Storage Operations

# Set environment variables for convenience
export AZURE_STORAGE_ACCOUNT=mystorageaccount
export AZURE_STORAGE_KEY=$(az storage account keys list \
    --account-name mystorageaccount \
    --resource-group myResourceGroup \
    --query '[0].value' --output tsv)

# Create container
az storage container create --name mycontainer

# Create container with public access
az storage container create --name public-container --public-access blob

# List containers
az storage container list --output table

# Upload blob
az storage blob upload \
    --container-name mycontainer \
    --name myfile.txt \
    --file /path/to/local/file.txt

# Upload directory
az storage blob upload-batch \
    --destination mycontainer \
    --source /path/to/local/directory

# List blobs
az storage blob list --container-name mycontainer --output table

# Download blob
az storage blob download \
    --container-name mycontainer \
    --name myfile.txt \
    --file /path/to/download/file.txt

# Download directory
az storage blob download-batch \
    --destination /path/to/local/directory \
    --source mycontainer

# Delete blob
az storage blob delete --container-name mycontainer --name myfile.txt

# Generate SAS token for blob
az storage blob generate-sas \
    --container-name mycontainer \
    --name myfile.txt \
    --permissions r \
    --expiry 2026-12-31T23:59:59Z \
    --output tsv

# Set blob tier
az storage blob set-tier \
    --container-name mycontainer \
    --name myfile.txt \
    --tier Cool

File Storage Operations

# Create file share
az storage share create --name myfileshare --quota 100

# List file shares
az storage share list --output table

# Create directory
az storage directory create --share-name myfileshare --name mydir

# Upload file
az storage file upload \
    --share-name myfileshare \
    --source /path/to/local/file.txt \
    --path mydir/file.txt

# List files
az storage file list --share-name myfileshare --path mydir --output table

# Download file
az storage file download \
    --share-name myfileshare \
    --path mydir/file.txt \
    --dest /path/to/download/file.txt

# Mount file share on Linux
sudo mount -t cifs //<storage-account>.file.core.windows.net/<share-name> /mnt/myshare \
    -o vers=3.0,username=<storage-account>,password=<storage-key>,dir_mode=0777,file_mode=0777

Queue Storage Operations

# Create queue
az storage queue create --name myqueue

# List queues
az storage queue list --output table

# Add message to queue
az storage message put --queue-name myqueue --content "Hello, World!"

# Peek at messages (without removing)
az storage message peek --queue-name myqueue

# Get messages (removes from queue)
az storage message get --queue-name myqueue

# Clear all messages
az storage message clear --queue-name myqueue

# Delete queue
az storage queue delete --name myqueue

Table Storage Operations

# Create table
az storage table create --name mytable

# List tables
az storage table list --output table

# Insert entity
az storage entity insert --table-name mytable \
    --entity PartitionKey=pk1 RowKey=rk1 Name=John Age=30

# Query entities
az storage entity query --table-name mytable

# Query with filter
az storage entity query --table-name mytable \
    --filter "PartitionKey eq 'pk1'"

# Delete entity
az storage entity delete --table-name mytable \
    --partition-key pk1 --row-key rk1

# Delete table
az storage table delete --name mytable

Microsoft Entra ID and RBAC

Microsoft Entra ID (formerly Azure Active Directory / Azure AD) provides identity and access management services. The CLI commands retain the az ad prefix.

Access ControlIdentity ManagementEntra ID TenantUsersGroupsService PrincipalsManaged IdentitiesRole DefinitionsRole AssignmentsScopesManagement GroupSubscriptionResource GroupResourceAccess ControlIdentity ManagementEntra ID TenantUsersGroupsService PrincipalsManaged IdentitiesRole DefinitionsRole AssignmentsScopesManagement GroupSubscriptionResource GroupResource

Key Concepts

  • Tenant: Dedicated instance of Microsoft Entra ID for an organisation
  • Service Principal: Identity for applications to access Azure resources
  • Managed Identity: Automatic identity management for Azure services
  • RBAC: Role-Based Access Control for fine-grained permissions
  • Built-in Roles: Owner, Contributor, Reader, and service-specific roles

User and Group Management

# List users
az ad user list --output table

# Create user
az ad user create \
    --display-name "John Smith" \
    --user-principal-name john@contoso.onmicrosoft.com \
    --password "SecureP@ssw0rd!"

# Show user details
az ad user show --id john@contoso.onmicrosoft.com

# Delete user
az ad user delete --id john@contoso.onmicrosoft.com

# List groups
az ad group list --output table

# Create group
az ad group create --display-name "DevOps Team" --mail-nickname devops-team

# Add user to group
az ad group member add \
    --group "DevOps Team" \
    --member-id <user-object-id>

# List group members
az ad group member list --group "DevOps Team" --output table

# Check group membership
az ad group member check \
    --group "DevOps Team" \
    --member-id <user-object-id>

Service Principals

# Create service principal
az ad sp create-for-rbac --name myServicePrincipal

# Create with specific role and scope
az ad sp create-for-rbac \
    --name myServicePrincipal \
    --role Contributor \
    --scopes /subscriptions/<subscription-id>/resourceGroups/myResourceGroup

# List service principals
az ad sp list --all --output table

# Show service principal details
az ad sp show --id <app-id>

# Reset service principal credentials
az ad sp credential reset --id <app-id>

# Delete service principal
az ad sp delete --id <app-id>

# Create managed identity
az identity create \
    --resource-group myResourceGroup \
    --name myManagedIdentity

# Assign managed identity to VM
az vm identity assign \
    --resource-group myResourceGroup \
    --name myVM \
    --identities myManagedIdentity

Role Assignments

# List role definitions
az role definition list --output table

# List built-in roles
az role definition list --query "[?roleType=='BuiltInRole'].{Name:roleName, Description:description}" --output table

# Show role definition details
az role definition list --name "Contributor"

# Assign role to user
az role assignment create \
    --assignee john@contoso.onmicrosoft.com \
    --role "Contributor" \
    --scope /subscriptions/<subscription-id>/resourceGroups/myResourceGroup

# Assign role to service principal
az role assignment create \
    --assignee <app-id> \
    --role "Reader" \
    --scope /subscriptions/<subscription-id>

# Assign role to group
az role assignment create \
    --assignee-object-id <group-object-id> \
    --assignee-principal-type Group \
    --role "Contributor" \
    --scope /subscriptions/<subscription-id>/resourceGroups/myResourceGroup

# List role assignments
az role assignment list --output table

# List role assignments for specific user
az role assignment list --assignee john@contoso.onmicrosoft.com --output table

# List role assignments for resource group
az role assignment list \
    --scope /subscriptions/<subscription-id>/resourceGroups/myResourceGroup \
    --output table

# Delete role assignment
az role assignment delete \
    --assignee john@contoso.onmicrosoft.com \
    --role "Contributor" \
    --scope /subscriptions/<subscription-id>/resourceGroups/myResourceGroup

Custom Role Definitions

# Create custom role from JSON
cat << 'EOF' > custom-role.json
{
  "Name": "Custom VM Operator",
  "Description": "Can start and stop VMs",
  "Actions": [
    "Microsoft.Compute/virtualMachines/start/action",
    "Microsoft.Compute/virtualMachines/powerOff/action",
    "Microsoft.Compute/virtualMachines/restart/action",
    "Microsoft.Compute/virtualMachines/read"
  ],
  "NotActions": [],
  "AssignableScopes": [
    "/subscriptions/<subscription-id>"
  ]
}
EOF

az role definition create --role-definition custom-role.json

# Update custom role
az role definition update --role-definition custom-role.json

# Delete custom role
az role definition delete --name "Custom VM Operator"

Azure Kubernetes Service (AKS)

AKS is a managed Kubernetes service for deploying and managing containerised applications.

AKS ClusterNode PoolsControl PlaneManaged by AzureSystem Node PoolUser Node Pool 1User Node Pool 2NodeNodeNodeNodeNodeAzure ContainerRegistryAzure MonitorEntra IDAKS ClusterNode PoolsControl PlaneManaged by AzureSystem Node PoolUser Node Pool 1User Node Pool 2NodeNodeNodeNodeNodeAzure ContainerRegistryAzure MonitorEntra ID

Key Concepts

  • Control Plane: Managed by Azure, includes API server, scheduler, etcd
  • Node Pools: Groups of nodes with the same configuration
  • System Node Pool: Runs critical system pods (CoreDNS, kube-proxy)
  • User Node Pools: Run application workloads

Creating AKS Clusters

# Create basic AKS cluster
az aks create \
    --resource-group myResourceGroup \
    --name myAKSCluster \
    --node-count 3 \
    --enable-addons monitoring \
    --generate-ssh-keys

# Create cluster with specific settings
az aks create \
    --resource-group myResourceGroup \
    --name myAKSCluster \
    --node-count 3 \
    --node-vm-size Standard_D2s_v3 \
    --kubernetes-version 1.33.0 \
    --network-plugin azure \
    --enable-managed-identity \
    --enable-addons monitoring \
    --generate-ssh-keys

# Create cluster with Azure CNI
# (--docker-bridge-address was removed when AKS moved to containerd)
az aks create \
    --resource-group myResourceGroup \
    --name myAKSCluster \
    --node-count 3 \
    --network-plugin azure \
    --vnet-subnet-id /subscriptions/<sub-id>/resourceGroups/<rg>/providers/Microsoft.Network/virtualNetworks/<vnet>/subnets/<subnet> \
    --dns-service-ip 10.2.0.10 \
    --service-cidr 10.2.0.0/24

# List available Kubernetes versions
az aks get-versions --location uksouth --output table

Managing AKS Clusters

# List AKS clusters
az aks list --output table

# Show cluster details
az aks show --resource-group myResourceGroup --name myAKSCluster

# Get cluster credentials
az aks get-credentials --resource-group myResourceGroup --name myAKSCluster

# Get credentials with admin access
az aks get-credentials --resource-group myResourceGroup --name myAKSCluster --admin

# Upgrade cluster (check available versions with `az aks get-versions`)
az aks upgrade \
    --resource-group myResourceGroup \
    --name myAKSCluster \
    --kubernetes-version 1.34.0

# Scale cluster
az aks scale \
    --resource-group myResourceGroup \
    --name myAKSCluster \
    --node-count 5

# Start cluster (if stopped)
az aks start --resource-group myResourceGroup --name myAKSCluster

# Stop cluster
az aks stop --resource-group myResourceGroup --name myAKSCluster

# Delete cluster
az aks delete --resource-group myResourceGroup --name myAKSCluster --yes

Node Pool Management

# List node pools
az aks nodepool list \
    --resource-group myResourceGroup \
    --cluster-name myAKSCluster \
    --output table

# Add node pool
az aks nodepool add \
    --resource-group myResourceGroup \
    --cluster-name myAKSCluster \
    --name gpunodepool \
    --node-count 2 \
    --node-vm-size Standard_NC4as_T4_v3 \
    --labels workload=gpu

# Add spot node pool (cost savings)
az aks nodepool add \
    --resource-group myResourceGroup \
    --cluster-name myAKSCluster \
    --name spotnodepool \
    --node-count 3 \
    --priority Spot \
    --eviction-policy Delete \
    --spot-max-price -1

# Scale node pool
az aks nodepool scale \
    --resource-group myResourceGroup \
    --cluster-name myAKSCluster \
    --name gpunodepool \
    --node-count 5

# Upgrade node pool
az aks nodepool upgrade \
    --resource-group myResourceGroup \
    --cluster-name myAKSCluster \
    --name gpunodepool \
    --kubernetes-version 1.34.0

# Delete node pool
az aks nodepool delete \
    --resource-group myResourceGroup \
    --cluster-name myAKSCluster \
    --name gpunodepool

# Enable cluster autoscaler
az aks nodepool update \
    --resource-group myResourceGroup \
    --cluster-name myAKSCluster \
    --name nodepool1 \
    --enable-cluster-autoscaler \
    --min-count 1 \
    --max-count 10

AKS with Azure Container Registry

# Create ACR
az acr create \
    --resource-group myResourceGroup \
    --name myacr \
    --sku Basic

# Attach ACR to AKS
az aks update \
    --resource-group myResourceGroup \
    --name myAKSCluster \
    --attach-acr myacr

# Or during cluster creation
az aks create \
    --resource-group myResourceGroup \
    --name myAKSCluster \
    --attach-acr myacr \
    --node-count 3 \
    --generate-ssh-keys

App Service

Azure App Service is a fully managed platform for building, deploying, and scaling web applications.

Source CodeBuildApp Service PlanWeb AppCustom DomainSSL CertificateDeployment SlotsProductionStagingDevSource CodeBuildApp Service PlanWeb AppCustom DomainSSL CertificateDeployment SlotsProductionStagingDev

Key Concepts

  • App Service Plan: Defines compute resources and pricing tier
  • Web App: The application hosted on the plan
  • Deployment Slots: Live apps with their own hostnames for staging
  • Scaling: Vertical (scale up) or horizontal (scale out)

Creating App Service

# Create App Service Plan
az appservice plan create \
    --name myAppServicePlan \
    --resource-group myResourceGroup \
    --sku B1 \
    --is-linux

# Create Web App
az webapp create \
    --resource-group myResourceGroup \
    --plan myAppServicePlan \
    --name mywebapp \
    --runtime "PYTHON:3.11"

# List available runtimes
az webapp list-runtimes --os-type linux

# Create Web App for containers
az webapp create \
    --resource-group myResourceGroup \
    --plan myAppServicePlan \
    --name mycontainerapp \
    --deployment-container-image-name nginx:latest

# List web apps
az webapp list --output table

# Show web app details
az webapp show --resource-group myResourceGroup --name mywebapp

Deploying Applications

# Deploy from local Git
az webapp deployment source config-local-git \
    --resource-group myResourceGroup \
    --name mywebapp

# Get deployment URL
az webapp deployment list-publishing-credentials \
    --resource-group myResourceGroup \
    --name mywebapp \
    --query scmUri --output tsv

# Deploy from GitHub
az webapp deployment source config \
    --resource-group myResourceGroup \
    --name mywebapp \
    --repo-url https://github.com/user/repo \
    --branch main \
    --manual-integration

# Deploy from ZIP
az webapp deployment source config-zip \
    --resource-group myResourceGroup \
    --name mywebapp \
    --src app.zip

# Deploy using Azure CLI
az webapp up \
    --resource-group myResourceGroup \
    --name mywebapp \
    --runtime "PYTHON:3.11"

# Restart web app
az webapp restart --resource-group myResourceGroup --name mywebapp

# View logs
az webapp log tail --resource-group myResourceGroup --name mywebapp

Configuration

# Set application settings (environment variables)
az webapp config appsettings set \
    --resource-group myResourceGroup \
    --name mywebapp \
    --settings KEY1=VALUE1 KEY2=VALUE2

# List application settings
az webapp config appsettings list \
    --resource-group myResourceGroup \
    --name mywebapp \
    --output table

# Set connection string
az webapp config connection-string set \
    --resource-group myResourceGroup \
    --name mywebapp \
    --settings MyDbConnection='Server=...' \
    --connection-string-type SQLAzure

# Configure startup command
az webapp config set \
    --resource-group myResourceGroup \
    --name mywebapp \
    --startup-file "gunicorn --bind=0.0.0.0 app:app"

# Enable application logging
az webapp log config \
    --resource-group myResourceGroup \
    --name mywebapp \
    --application-logging filesystem \
    --level verbose

# Configure custom domain
az webapp config hostname add \
    --resource-group myResourceGroup \
    --webapp-name mywebapp \
    --hostname www.example.com

Scaling

# Scale up (change pricing tier; Premium v4 (P1V4) is the latest
# generation where regionally available)
az appservice plan update \
    --resource-group myResourceGroup \
    --name myAppServicePlan \
    --sku P1V3

# Scale out (increase instances)
az appservice plan update \
    --resource-group myResourceGroup \
    --name myAppServicePlan \
    --number-of-workers 3

# Configure autoscale
az monitor autoscale create \
    --resource-group myResourceGroup \
    --resource myAppServicePlan \
    --resource-type Microsoft.Web/serverfarms \
    --name autoscale-config \
    --min-count 1 \
    --max-count 10 \
    --count 1

# Add autoscale rule
az monitor autoscale rule create \
    --resource-group myResourceGroup \
    --autoscale-name autoscale-config \
    --condition "CpuPercentage > 70 avg 5m" \
    --scale out 1

Deployment Slots

# Create deployment slot
az webapp deployment slot create \
    --resource-group myResourceGroup \
    --name mywebapp \
    --slot staging

# List slots
az webapp deployment slot list \
    --resource-group myResourceGroup \
    --name mywebapp \
    --output table

# Deploy to slot
az webapp deployment source config-zip \
    --resource-group myResourceGroup \
    --name mywebapp \
    --slot staging \
    --src app.zip

# Swap slots
az webapp deployment slot swap \
    --resource-group myResourceGroup \
    --name mywebapp \
    --slot staging \
    --target-slot production

# Configure slot settings (sticky)
az webapp config appsettings set \
    --resource-group myResourceGroup \
    --name mywebapp \
    --slot staging \
    --slot-settings IS_STAGING=true

Azure Functions

Azure Functions is a serverless compute service for running event-triggered code.

BindingsTriggersHTTPTimerQueueBlobEvent HubAzure FunctionInputOutputQueueBlobCosmos DBHTTP ResponseBindingsTriggersHTTPTimerQueueBlobEvent HubAzure FunctionInputOutputQueueBlobCosmos DBHTTP Response

Key Concepts

  • Triggers: Events that cause a function to run
  • Bindings: Declarative connections to other services
  • Function App: Container for one or more functions
  • Hosting Plans: Consumption (pay per execution), Premium, or Dedicated

Creating Functions

# Create Function App (Python 3.12 is the last version supported on
# Linux Consumption; use 3.13 on Flex Consumption/Premium/App Service plans)
az functionapp create \
    --resource-group myResourceGroup \
    --consumption-plan-location uksouth \
    --runtime python \
    --runtime-version 3.12 \
    --functions-version 4 \
    --name myfunctionapp \
    --storage-account mystorageaccount

# Create with Premium plan
az functionapp plan create \
    --resource-group myResourceGroup \
    --name myPremiumPlan \
    --location uksouth \
    --sku EP1

az functionapp create \
    --resource-group myResourceGroup \
    --plan myPremiumPlan \
    --runtime python \
    --runtime-version 3.13 \
    --functions-version 4 \
    --name myfunctionapp \
    --storage-account mystorageaccount

# List function apps
az functionapp list --output table

# Show function app details
az functionapp show --resource-group myResourceGroup --name myfunctionapp

Local Development

# Install Azure Functions Core Tools
npm install -g azure-functions-core-tools@4 --unsafe-perm true

# Create new function project
func init MyFunctionProject --python

# Create new function
cd MyFunctionProject
func new --name HttpTrigger --template "HTTP trigger"

# Run locally
func start

# Test locally
curl http://localhost:7071/api/HttpTrigger?name=Azure

Deploying Functions

# Deploy from local project
func azure functionapp publish myfunctionapp

# Deploy from ZIP
az functionapp deployment source config-zip \
    --resource-group myResourceGroup \
    --name myfunctionapp \
    --src functionapp.zip

# Deploy from GitHub
az functionapp deployment source config \
    --resource-group myResourceGroup \
    --name myfunctionapp \
    --repo-url https://github.com/user/repo \
    --branch main

# View deployment status
az functionapp deployment source show \
    --resource-group myResourceGroup \
    --name myfunctionapp

Configuration and Bindings

# Set application settings
az functionapp config appsettings set \
    --resource-group myResourceGroup \
    --name myfunctionapp \
    --settings "MyStorageConnection=..." "ApiKey=..."

# List settings
az functionapp config appsettings list \
    --resource-group myResourceGroup \
    --name myfunctionapp \
    --output table

# Get function URL
az functionapp function show \
    --resource-group myResourceGroup \
    --name myfunctionapp \
    --function-name HttpTrigger \
    --query invokeUrlTemplate --output tsv

Example Function with Bindings

# function_app.py
import azure.functions as func
import logging

app = func.FunctionApp()

# HTTP trigger with queue output binding
@app.route(route="orders", methods=["POST"])
@app.queue_output(arg_name="msg", queue_name="orders", connection="AzureStorageConnection")
def create_order(req: func.HttpRequest, msg: func.Out[str]) -> func.HttpResponse:
    order = req.get_json()
    msg.set(str(order))
    return func.HttpResponse("Order created", status_code=201)

# Queue trigger with blob output binding
@app.queue_trigger(arg_name="msg", queue_name="orders", connection="AzureStorageConnection")
@app.blob_output(arg_name="outputblob", path="processed/{rand-guid}.json", connection="AzureStorageConnection")
def process_order(msg: func.QueueMessage, outputblob: func.Out[str]):
    logging.info(f"Processing order: {msg.get_body().decode()}")
    outputblob.set(msg.get_body().decode())

# Timer trigger
@app.timer_trigger(schedule="0 */5 * * * *", arg_name="timer")
def scheduled_task(timer: func.TimerRequest):
    logging.info("Timer function executed")

# Blob trigger
@app.blob_trigger(arg_name="blob", path="uploads/{name}", connection="AzureStorageConnection")
def process_upload(blob: func.InputStream):
    logging.info(f"Processing blob: {blob.name}, Size: {blob.length} bytes")

Monitoring Functions

# View logs
az functionapp log tail --resource-group myResourceGroup --name myfunctionapp

# View execution history
az monitor metrics list \
    --resource /subscriptions/<sub-id>/resourceGroups/myResourceGroup/providers/Microsoft.Web/sites/myfunctionapp \
    --metric "FunctionExecutionCount" \
    --interval PT1H

# Enable Application Insights
az functionapp config appsettings set \
    --resource-group myResourceGroup \
    --name myfunctionapp \
    --settings "APPINSIGHTS_INSTRUMENTATIONKEY=<instrumentation-key>"

Container Instances and Container Apps

Azure provides multiple container hosting options for different use cases.

Container OptionsAzure ContainerInstancesSimple, fastdeploymentAzure Container AppsMicroservices,scalingAzure KubernetesServiceFull orchestrationSimple TasksMicroservicesComplex WorkloadsSingle ContainerGroupsManaged KubernetesFull KubernetesControlContainer OptionsAzure ContainerInstancesSimple, fastdeploymentAzure Container AppsMicroservices,scalingAzure KubernetesServiceFull orchestrationSimple TasksMicroservicesComplex WorkloadsSingle ContainerGroupsManaged KubernetesFull KubernetesControl

Azure Container Instances (ACI)

# Create container instance
az container create \
    --resource-group myResourceGroup \
    --name mycontainer \
    --image nginx:latest \
    --dns-name-label mycontainer \
    --ports 80

# Create with environment variables
az container create \
    --resource-group myResourceGroup \
    --name myapp \
    --image myacr.azurecr.io/myapp:latest \
    --registry-login-server myacr.azurecr.io \
    --registry-username myacr \
    --registry-password <password> \
    --dns-name-label myapp \
    --ports 8080 \
    --environment-variables DB_HOST=mydb.database.azure.com API_KEY=secret123 \
    --cpu 2 \
    --memory 4

# Create multi-container group from YAML
cat << 'EOF' > container-group.yaml
apiVersion: 2021-10-01
location: uksouth
name: mycontainergroup
properties:
  containers:
  - name: frontend
    properties:
      image: nginx
      ports:
      - port: 80
      resources:
        requests:
          cpu: 1.0
          memoryInGB: 1.5
  - name: backend
    properties:
      image: myacr.azurecr.io/backend:latest
      ports:
      - port: 8080
      resources:
        requests:
          cpu: 1.0
          memoryInGB: 1.5
  osType: Linux
  ipAddress:
    type: Public
    ports:
    - protocol: tcp
      port: 80
EOF

az container create \
    --resource-group myResourceGroup \
    --file container-group.yaml

# List container instances
az container list --output table

# Show container details
az container show --resource-group myResourceGroup --name mycontainer

# View logs
az container logs --resource-group myResourceGroup --name mycontainer

# Attach to container (interactive)
az container attach --resource-group myResourceGroup --name mycontainer

# Execute command in container
az container exec \
    --resource-group myResourceGroup \
    --name mycontainer \
    --exec-command "/bin/bash"

# Restart container
az container restart --resource-group myResourceGroup --name mycontainer

# Delete container
az container delete --resource-group myResourceGroup --name mycontainer --yes

Azure Container Apps

# Create Container Apps environment
az containerapp env create \
    --name myEnvironment \
    --resource-group myResourceGroup \
    --location uksouth

# Create Container App
az containerapp create \
    --name mycontainerapp \
    --resource-group myResourceGroup \
    --environment myEnvironment \
    --image nginx:latest \
    --target-port 80 \
    --ingress external \
    --min-replicas 1 \
    --max-replicas 10

# Create from ACR with secrets
az containerapp create \
    --name myapp \
    --resource-group myResourceGroup \
    --environment myEnvironment \
    --image myacr.azurecr.io/myapp:latest \
    --registry-server myacr.azurecr.io \
    --registry-username myacr \
    --registry-password <password> \
    --target-port 8080 \
    --ingress external \
    --env-vars "DB_HOST=mydb.database.azure.com" "API_KEY=secretref:api-key" \
    --secrets "api-key=mysecretvalue"

# List Container Apps
az containerapp list --output table

# Show Container App details
az containerapp show \
    --resource-group myResourceGroup \
    --name mycontainerapp

# Update Container App
az containerapp update \
    --resource-group myResourceGroup \
    --name mycontainerapp \
    --image nginx:1.25

# Configure scaling rules
az containerapp update \
    --resource-group myResourceGroup \
    --name mycontainerapp \
    --min-replicas 2 \
    --max-replicas 20 \
    --scale-rule-name http-rule \
    --scale-rule-type http \
    --scale-rule-http-concurrency 100

# View logs
az containerapp logs show \
    --resource-group myResourceGroup \
    --name mycontainerapp

# Create revision
az containerapp revision copy \
    --resource-group myResourceGroup \
    --name mycontainerapp \
    --image myacr.azurecr.io/myapp:v2

# List revisions
az containerapp revision list \
    --resource-group myResourceGroup \
    --name mycontainerapp \
    --output table

# Traffic splitting between revisions
az containerapp ingress traffic set \
    --resource-group myResourceGroup \
    --name mycontainerapp \
    --revision-weight mycontainerapp--rev1=80 mycontainerapp--rev2=20

# Delete Container App
az containerapp delete --resource-group myResourceGroup --name mycontainerapp --yes

Virtual Networks and NSGs

Azure Virtual Networks provide isolated network environments for Azure resources.

Virtual Network 10.0.0.0/16Subnet C - 10.0.3.0/24Subnet B - 10.0.2.0/24Subnet A - 10.0.1.0/24VM1VM2Web ServerApp ServerDatabaseInternetNSGVPN GatewayNSGNSGVirtual Network 10.0.0.0/16Subnet C - 10.0.3.0/24Subnet B - 10.0.2.0/24Subnet A - 10.0.1.0/24VM1VM2Web ServerApp ServerDatabaseInternetNSGVPN GatewayNSGNSG

Key Concepts

  • Virtual Network (VNet): Logically isolated network in Azure
  • Subnet: Segment of a VNet with its own address range
  • Network Security Group (NSG): Firewall rules for network traffic
  • Service Endpoints: Secure connectivity to Azure services
  • Private Endpoints: Private IP for Azure PaaS services

Creating Virtual Networks

# Create virtual network
az network vnet create \
    --resource-group myResourceGroup \
    --name myVNet \
    --address-prefix 10.0.0.0/16 \
    --subnet-name default \
    --subnet-prefix 10.0.1.0/24

# List virtual networks
az network vnet list --output table

# Show VNet details
az network vnet show --resource-group myResourceGroup --name myVNet

# Add subnet
az network vnet subnet create \
    --resource-group myResourceGroup \
    --vnet-name myVNet \
    --name backend \
    --address-prefix 10.0.2.0/24

# List subnets
az network vnet subnet list \
    --resource-group myResourceGroup \
    --vnet-name myVNet \
    --output table

# Update subnet
az network vnet subnet update \
    --resource-group myResourceGroup \
    --vnet-name myVNet \
    --name backend \
    --network-security-group myNSG

# Delete subnet
az network vnet subnet delete \
    --resource-group myResourceGroup \
    --vnet-name myVNet \
    --name backend

Network Security Groups

# Create NSG
az network nsg create \
    --resource-group myResourceGroup \
    --name myNSG

# List NSGs
az network nsg list --output table

# Show NSG rules
az network nsg rule list \
    --resource-group myResourceGroup \
    --nsg-name myNSG \
    --output table

# Add inbound rule (allow SSH)
az network nsg rule create \
    --resource-group myResourceGroup \
    --nsg-name myNSG \
    --name AllowSSH \
    --priority 100 \
    --direction Inbound \
    --access Allow \
    --protocol Tcp \
    --source-address-prefixes '*' \
    --source-port-ranges '*' \
    --destination-address-prefixes '*' \
    --destination-port-ranges 22

# Add inbound rule (allow HTTP/HTTPS)
az network nsg rule create \
    --resource-group myResourceGroup \
    --nsg-name myNSG \
    --name AllowWeb \
    --priority 110 \
    --direction Inbound \
    --access Allow \
    --protocol Tcp \
    --source-address-prefixes Internet \
    --source-port-ranges '*' \
    --destination-address-prefixes '*' \
    --destination-port-ranges 80 443

# Add inbound rule (deny all)
az network nsg rule create \
    --resource-group myResourceGroup \
    --nsg-name myNSG \
    --name DenyAll \
    --priority 4096 \
    --direction Inbound \
    --access Deny \
    --protocol '*' \
    --source-address-prefixes '*' \
    --source-port-ranges '*' \
    --destination-address-prefixes '*' \
    --destination-port-ranges '*'

# Add outbound rule
az network nsg rule create \
    --resource-group myResourceGroup \
    --nsg-name myNSG \
    --name AllowStorageOutbound \
    --priority 100 \
    --direction Outbound \
    --access Allow \
    --protocol Tcp \
    --source-address-prefixes VirtualNetwork \
    --source-port-ranges '*' \
    --destination-address-prefixes Storage \
    --destination-port-ranges 443

# Associate NSG with subnet
az network vnet subnet update \
    --resource-group myResourceGroup \
    --vnet-name myVNet \
    --name default \
    --network-security-group myNSG

# Associate NSG with NIC
az network nic update \
    --resource-group myResourceGroup \
    --name myVMNic \
    --network-security-group myNSG

# Delete NSG rule
az network nsg rule delete \
    --resource-group myResourceGroup \
    --nsg-name myNSG \
    --name AllowSSH

Public IP and Load Balancer

# Create public IP
az network public-ip create \
    --resource-group myResourceGroup \
    --name myPublicIP \
    --sku Standard \
    --allocation-method Static

# Create load balancer
az network lb create \
    --resource-group myResourceGroup \
    --name myLoadBalancer \
    --sku Standard \
    --public-ip-address myPublicIP \
    --frontend-ip-name myFrontEnd \
    --backend-pool-name myBackEndPool

# Create health probe
az network lb probe create \
    --resource-group myResourceGroup \
    --lb-name myLoadBalancer \
    --name myHealthProbe \
    --protocol tcp \
    --port 80

# Create load balancer rule
az network lb rule create \
    --resource-group myResourceGroup \
    --lb-name myLoadBalancer \
    --name myHTTPRule \
    --protocol tcp \
    --frontend-port 80 \
    --backend-port 80 \
    --frontend-ip-name myFrontEnd \
    --backend-pool-name myBackEndPool \
    --probe-name myHealthProbe

VNet Peering

# Create VNet peering
az network vnet peering create \
    --resource-group myResourceGroup \
    --name VNet1ToVNet2 \
    --vnet-name myVNet1 \
    --remote-vnet /subscriptions/<sub-id>/resourceGroups/<rg>/providers/Microsoft.Network/virtualNetworks/myVNet2 \
    --allow-vnet-access

# List peerings
az network vnet peering list \
    --resource-group myResourceGroup \
    --vnet-name myVNet1 \
    --output table

# Delete peering
az network vnet peering delete \
    --resource-group myResourceGroup \
    --name VNet1ToVNet2 \
    --vnet-name myVNet1

Quick Reference

Task Command
Login az login
Set subscription az account set --subscription "name"
Create resource group az group create --name rg --location uksouth
Create VM az vm create --resource-group rg --name vm --image Ubuntu2204
Start/Stop VM az vm start/stop --resource-group rg --name vm
Create storage account az storage account create --name sa --resource-group rg
Upload blob az storage blob upload --container-name c --name n --file f
Create AKS cluster az aks create --resource-group rg --name aks --node-count 3
Get AKS credentials az aks get-credentials --resource-group rg --name aks
Create web app az webapp create --resource-group rg --plan plan --name app
Deploy web app az webapp deployment source config-zip --resource-group rg --name app --src app.zip
Create function app az functionapp create --resource-group rg --name func --storage-account sa
Create container instance az container create --resource-group rg --name ci --image img
Create VNet az network vnet create --resource-group rg --name vnet --address-prefix 10.0.0.0/16
Create NSG az network nsg create --resource-group rg --name nsg
Add NSG rule az network nsg rule create --resource-group rg --nsg-name nsg --name rule
Assign role az role assignment create --assignee user --role "Role" --scope scope
List resources az resource list --resource-group rg --output table

Common Issues and Solutions

Issue Solution
AuthorizationFailed error Check role assignments with az role assignment list --assignee <user>. Ensure correct scope and permissions.
ResourceNotFound error Verify resource group and resource names. Check subscription context with az account show.
VM not starting Check quota limits: az vm list-usage --location uksouth. Request increase if needed.
Cannot SSH to VM Verify NSG rules allow port 22. Check public IP is assigned. Use az vm run-command as alternative.
Storage access denied Check firewall rules and network access. Verify SAS token or storage key is valid and not expired.
AKS cluster unreachable Run az aks get-credentials to refresh kubeconfig. Check cluster status with az aks show.
Web app deployment fails Check deployment logs: az webapp log tail. Verify runtime matches application. Check startup command.
Function not triggering Verify connection strings for bindings. Check Application Insights for errors. Review function.json configuration.
Container instance failing Check container logs: az container logs. Verify image pull permissions. Check resource limits.
VNet peering not working Ensure peering is created on both VNets. Check for overlapping address spaces. Verify allow-vnet-access is enabled.
NSG rules not applying Check rule priority (lower number = higher priority). Verify NSG is associated with subnet or NIC.
Service principal expired Reset credentials: az ad sp credential reset --id <app-id>. Update application configuration.
Subscription quota exceeded Request increase via Azure Portal or az quota request create. Consider different region.
Slow Azure CLI commands Update CLI: az upgrade. Use --no-wait for async operations. Use JMESPath queries to reduce output.

Related Topics

The following topics complement this Azure cheatsheet and would be valuable additions:

  1. Terraform - Infrastructure as Code for Azure resources, enabling repeatable deployments and version-controlled infrastructure
  2. Azure DevOps / GitHub Actions - CI/CD pipelines for automated deployment to Azure services
  3. Prometheus & Grafana - Monitoring and observability for Azure workloads, especially AKS clusters
  4. Helm - Package management for Kubernetes applications on AKS
  5. Ansible - Configuration management and automation for Azure VMs and resources
  6. Container Security - Image scanning, runtime security, and best practices for Azure container services