48 - Azure¶
Previous: 47 - Terraform | Index: All guides | Next: 49 - Azure VM + Linux + Ollama
Quick reference for Microsoft Azure with the Azure CLI: core concepts, the most used services, security, cost and infrastructure as code.
Last verified: 2026-09-27. For newer changes, check the Official docs links in the Introduction.
Introduction¶
Before you start¶
You should know: what servers, containers and APIs are (01 - Core Concepts sections 7 and 13), terminal use (03), and ideally Docker (43), since containers are the easiest way to deploy. You need an Azure account (a free account includes credits).
The problem it solves: running your app for real users needs computers that are always on, reachable from the internet, backed up, secure, and able to grow with traffic. Buying and operating your own servers means large upfront costs, a server room, and people to replace broken hardware at night.
Before the cloud: companies bought servers, rented space in data centres and planned capacity months ahead, often paying for much more than they used. Cloud platforms (AWS from 2006, Azure from 2010) let you rent exactly what you need by the minute, from raw virtual machines up to fully managed services where the provider runs everything except your code.
Think of it like: renting instead of buying. Electricity from the grid instead of your own power station: you pay for what you use, can use a lot more tomorrow, and someone else maintains the plant. The trade-off is that the bill grows with use, so you must watch it.
What is Azure?¶
Microsoft Azure is a cloud platform: instead of buying and running your own servers, you rent computing power, storage, databases, networking and AI services from Microsoft's data centres around the world and pay only for what you use. You create and manage everything through the Azure Portal (website, portal.azure.com), the Azure CLI (az commands in a terminal), SDKs (Python libraries) or infrastructure-as-code files (Bicep / Terraform).
Every thing you create (a VM, a storage account, a database) is a resource. Resources live in resource groups (folders), which belong to a subscription (the billing account), inside a tenant (your organisation's identity directory, Microsoft Entra ID).
Tenant (Microsoft Entra ID: users, groups, apps)
+-- Subscription (billing + limits) e.g. "Pay-As-You-Go"
+-- Resource group (folder, one lifecycle) e.g. "rg-sales-api-dev"
+-- Resources VM, storage account, container app, key vault ...
(each in a region) e.g. swedencentral, westeurope
Service models¶
| Model | You manage | Azure manages | Examples |
|---|---|---|---|
| IaaS (Infrastructure) | OS, runtime, app, data | Hardware, network, virtualisation | Virtual Machines |
| PaaS (Platform) | App and data | OS, patching, scaling, runtime | App Service, Container Apps, Azure SQL |
| Serverless | Only code / container | Everything, scales to zero | Azure Functions, Container Apps (min 0) |
| SaaS / AI services | Just use it | Everything | Azure OpenAI, AI Search, Microsoft 365 |
Why use it?¶
- No hardware: create a server, database or GPU machine in minutes; delete it when done.
- Pay as you go: pay per second / hour / request; stop resources to stop most costs.
- Scale: from one small container to thousands of instances, in regions worldwide.
- Managed services: Azure handles backups, patching, high availability and security updates.
- Security and compliance: identity (Entra ID), role-based access, Key Vault, EU data regions.
- Microsoft ecosystem: integrates with Microsoft 365, GitHub, VS Code and Azure OpenAI.
Key terms¶
| Term | Meaning |
|---|---|
| Tenant | Your organisation's directory (Microsoft Entra ID) |
| Subscription | Billing unit with its own limits and permissions |
| Resource group (RG) | Container for related resources; delete the RG = delete everything in it |
| Resource | One service instance: VM, storage account, web app ... |
| Region | Physical data-centre location (swedencentral, westeurope, northeurope) |
| SKU / tier | Size and price level of a resource (Basic, Standard, B1, S0) |
| Resource provider | Azure service namespace that must be registered (Microsoft.App) |
| RBAC | Role-based access control: who can do what, on which scope |
| Managed identity | An identity Azure gives your app so it can access other resources without passwords |
| Service principal | An identity for automation / CI pipelines |
Where it fits: deploy containers from 43 - Docker and APIs from 40 - FastAPI; a full VM + LLM walkthrough is in 49 - Azure VM + Linux + Ollama. Automate it with 47 - Terraform and 44 - GitHub Actions; run Kubernetes on AKS with 46.
Official docs¶
Where to read the latest, authoritative documentation:
| Resource | Link |
|---|---|
| Azure documentation | https://learn.microsoft.com/en-us/azure/ |
| Azure CLI | https://learn.microsoft.com/en-us/cli/azure/ |
| Azure CLI command reference | https://learn.microsoft.com/en-us/cli/azure/reference-index |
| Azure Container Apps | https://learn.microsoft.com/en-us/azure/container-apps/ |
| Azure AI Foundry (incl. Azure OpenAI) | https://learn.microsoft.com/en-us/azure/ai-foundry/ |
| Bicep | https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/ |
| Pricing calculator | https://azure.microsoft.com/en-us/pricing/calculator/ |
| Resource naming abbreviations | https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/resource-abbreviations |
Contents¶
- Flags and Parameters
- Install, Log In, Cloud Shell
- Subscriptions and Account
- Resource Groups
- Regions, Providers and Quotas
- Output Formats and --query
- Virtual Machines
- Storage Accounts and Blobs
- Container Registry (ACR)
- Container Apps
- App Service (Web Apps)
- Azure Functions
- Key Vault (Secrets)
- Databases
- Networking
- Identity and Access (RBAC)
- Managed Identity and Service Principals
- Azure SDK for Python
- Azure OpenAI
- Monitoring and Logs
- Cost Management
- Tags, Locks and Cleanup
- Infrastructure as Code (Bicep)
- End to End: Deploy a FastAPI Container
- Which Service to Use
- Naming Conventions
- Troubleshooting
- Try It
0. Flags and Parameters¶
How
azcommands are built and what the common flags mean.az <group> [<sub-group>] <action> --flags; most flags work the same across all services.Use this when you see
az containerapp create -g rg -n api --image ... --ingress externaland want to know what each part does.
az storage blob upload --account-name stsales -c data -n sales.csv -f ./sales.csv --auth-mode login
| | | | | | | | |
| | | | | | | | +-- use your Entra login, not keys
| | | | | | | +------------------ local file to upload
| | | | | | +-------------------------------- blob name in Azure
| | | | | +----------------------------------------- container (folder)
| | | | +------------------------------------------------------------------ storage account
| | | +-------------------------------------------------------------------------- action
| | +-------------------------------------------------------------------------------- sub-group: blobs
| +----------------------------------------------------------------------------------------- group: storage
+--------------------------------------------------------------------------------------------- Azure CLI
Help anywhere: az storage blob upload --help, az find "container app" (examples from docs).
Global flags (work on every command)¶
| Flag | Long form | Meaning | Example |
|---|---|---|---|
-g |
--resource-group |
Resource group | -g rg-demo |
-n |
--name |
Resource name | -n myvm |
-l |
--location |
Region | -l swedencentral |
-o |
--output |
json, jsonc, table, tsv, yaml, none |
-o table |
--query |
JMESPath filter on the JSON result | --query "[].name" |
|
--subscription |
Run against another subscription | --subscription <id> |
|
--ids |
Target resources by full ID instead of -g / -n |
--ids $(az vm list --query "[].id" -o tsv) |
|
--yes / -y |
Do not ask for confirmation | az group delete -n rg --yes |
|
--no-wait |
Start the operation and return immediately | --no-wait |
|
--tags |
Key=value labels | --tags env=dev owner=harman |
|
--verbose / --debug |
More output / full HTTP details for troubleshooting | --debug |
|
--only-show-errors |
Hide warnings |
Common service flags¶
| Flag | Used in | Meaning |
|---|---|---|
--sku |
most create commands | Size / pricing tier (Basic, Standard_LRS, B1, S0) |
--image |
vm, containerapp, webapp | OS image (VM) or container image |
--size |
vm | VM size (Standard_B2s) |
--admin-username |
vm | Login user name |
--generate-ssh-keys |
vm | Create / reuse ~/.ssh/id_rsa keys |
--auth-mode login |
storage | Use your Entra identity + RBAC instead of account keys |
--target-port |
containerapp | Port your container listens on |
--ingress |
containerapp | external (internet) or internal (only inside the environment) |
--min-replicas / --max-replicas |
containerapp | Scaling limits; 0 = scale to zero (no cost when idle) |
--registry-server |
containerapp | Registry to pull the image from |
--runtime |
webapp, functionapp | Language runtime (PYTHON:3.12) |
--settings |
webapp config | App settings = environment variables |
--assignee / --role / --scope |
role assignment | Who / which role / on which resource |
1. Install, Log In, Cloud Shell¶
Getting the Azure CLI and signing in. Install
az, thenaz loginopens the browser; Cloud Shell in the Portal hasazpre-installed.Use it as the first step on any machine; Cloud Shell when you cannot install anything locally.
winget install -e --id Microsoft.AzureCLI # Windows
brew install azure-cli # Mac
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash # Ubuntu
az --version
az upgrade # update the CLI
az login # browser login
az login --use-device-code # login from a machine without browser (VM, SSH)
az logout
Cloud Shell: click the >_ icon in the Portal; Bash or PowerShell with az, git, docker CLI and a small persistent disk.
2. Subscriptions and Account¶
Choosing which subscription your commands act on.
az accountlists and switches subscriptions; the selected one is used by every later command.Use this when you have several subscriptions (work, personal, trial) or resources "disappear" (wrong subscription).
az account show -o table # current subscription
az account list -o table # all subscriptions you can access
az account set --subscription "<name-or-id>" # switch
az account show --query id -o tsv # current subscription ID
az ad signed-in-user show --query "{name:displayName, id:id}" -o table # who am I
3. Resource Groups¶
Folders for resources that share a lifecycle. Create one per project / environment; everything inside can be listed, tagged and deleted together. Always create a resource group first; delete it to clean up a whole project.
az group create -n rg-sales-dev -l swedencentral
az group list -o table
az group show -n rg-sales-dev
az resource list -g rg-sales-dev -o table # everything inside
az group delete -n rg-sales-dev --yes --no-wait # delete group AND all resources (permanent)
az group exists -n rg-sales-dev # true / false
Tip: one RG per app per environment (rg-sales-dev, rg-sales-prod).
4. Regions, Providers and Quotas¶
Where resources run, which services are enabled, and how much you are allowed to create. Regions are chosen per resource; providers must be registered once per subscription; quotas limit vCPUs etc.
Use it to answer questions like "Not available in region", "provider not registered" or "quota exceeded" errors.
az account list-locations --query "[].name" -o tsv # all regions
az vm list-sizes -l swedencentral -o table # VM sizes in a region
az vm list-usage -l swedencentral -o table # vCPU quota used / limit
az provider list --query "[?registrationState=='Registered'].namespace" -o table
az provider register -n Microsoft.App # Container Apps
az provider register -n Microsoft.ContainerRegistry
az provider show -n Microsoft.App --query registrationState -o tsv
Choose a region close to your users; EU data: swedencentral, westeurope, northeurope, germanywestcentral, francecentral.
5. Output Formats and --query¶
Controlling how results look and picking only the fields you need.
-ochanges the format;--queryuses JMESPath to filter and reshape the JSON.Use it for readable tables for humans (
-o table), single values for scripts (-o tsv).
-o |
Result |
|---|---|
json |
Full JSON (default) |
table |
Readable table |
tsv |
Plain values, tab separated (store in variables) |
yaml |
YAML |
none |
Nothing (only errors) |
--query |
Returns |
|---|---|
"name" |
One field |
"[].name" |
Field from every item in a list |
"[0]" |
First item |
"[?location=='swedencentral'].name" |
Filter, then pick a field |
"[?contains(name, 'api')]" |
Items whose name contains "api" |
"[].{Name:name, RG:resourceGroup}" |
New object with renamed fields (good with -o table) |
"length([])" |
Count |
$IP = az vm show -d -g rg-demo -n myvm --query publicIps -o tsv
az vm list -d --query "[].{Name:name, State:powerState, IP:publicIps}" -o table
6. Virtual Machines¶
Full computers in the cloud where you control the OS (IaaS). Pick an image, size and login method; Azure creates disk, network card, public IP and NSG with it.
Use it for custom software, GPU workloads, LLM hosting, anything needing full OS control. Full walkthrough: 49 - Azure VM + Linux + Ollama.
az vm create -g rg-demo -n myvm \
--image Ubuntu2404 --size Standard_B2s \
--admin-username azureuser --generate-ssh-keys \
--public-ip-sku Standard
az vm list -d -o table # status and IPs
az vm start -g rg-demo -n myvm
az vm deallocate -g rg-demo -n myvm # stop and release compute (billing stops)
az vm restart -g rg-demo -n myvm
az vm resize -g rg-demo -n myvm --size Standard_D4s_v5
az vm auto-shutdown -g rg-demo -n myvm --time 1900 # daily shutdown at 19:00 UTC
az vm run-command invoke -g rg-demo -n myvm --command-id RunShellScript --scripts "uptime"
az vm delete -g rg-demo -n myvm --yes # disk / IP / NIC may remain: delete the RG to be sure
stop keeps billing for compute; deallocate stops compute billing (disk still billed).
7. Storage Accounts and Blobs¶
Cheap, durable storage for files (blobs), plus queues, tables and file shares. A storage account holds containers; containers hold blobs (files). Access with Entra login + RBAC or keys / SAS.
Use it for data files for analysis, model files, backups, images, static websites.
az storage account create -n stsalesdev123 -g rg-demo -l swedencentral --sku Standard_LRS
# Give yourself data access (needed for --auth-mode login)
az role assignment create --assignee $(az ad signed-in-user show --query id -o tsv) \
--role "Storage Blob Data Contributor" \
--scope $(az storage account show -n stsalesdev123 -g rg-demo --query id -o tsv)
az storage container create --account-name stsalesdev123 -n data --auth-mode login
az storage blob upload --account-name stsalesdev123 -c data -n sales.csv -f ./sales.csv --auth-mode login
az storage blob upload-batch --account-name stsalesdev123 -d data -s ./folder --auth-mode login
az storage blob list --account-name stsalesdev123 -c data --auth-mode login -o table
az storage blob download --account-name stsalesdev123 -c data -n sales.csv -f ./copy.csv --auth-mode login
| SKU | Redundancy |
|---|---|
Standard_LRS |
3 copies in one data centre (cheapest) |
Standard_ZRS |
Copies across availability zones |
Standard_GRS |
Copies to a second region |
Storage account names: 3 to 24 lowercase letters and digits, globally unique. Role assignments can take a few minutes to apply.
8. Container Registry (ACR)¶
Private Docker image storage in Azure. Push images with Docker, or let ACR build them in the cloud with
az acr build.Use it for storing images for Container Apps, App Service or VMs. Docker basics: 43 - Docker.
az acr create -g rg-demo -n acrsalesdev --sku Basic
az acr login -n acrsalesdev # docker login for this registry
docker tag myapi:1.0 acrsalesdev.azurecr.io/myapi:1.0
docker push acrsalesdev.azurecr.io/myapi:1.0
az acr build -r acrsalesdev -t myapi:1.0 . # build in Azure, no local Docker needed
az acr repository list -n acrsalesdev -o table
az acr repository show-tags -n acrsalesdev --repository myapi -o table
9. Container Apps¶
Serverless containers: run any Docker image with HTTPS, autoscaling and scale-to-zero, without managing servers or Kubernetes. Apps run in an environment; set image, port and ingress; Azure provides a public HTTPS URL.
Use it for APIs (FastAPI), web apps, background workers. Usually the easiest way to run a container in Azure.
az extension add --name containerapp --upgrade
az provider register -n Microsoft.App
az provider register -n Microsoft.OperationalInsights
# One command: build from source (Dockerfile), create ACR + environment + app
az containerapp up -n sales-api -g rg-demo -l swedencentral \
--source . --ingress external --target-port 8000
# Or step by step with an existing image
az containerapp env create -n cae-demo -g rg-demo -l swedencentral
az containerapp create -n sales-api -g rg-demo --environment cae-demo \
--image acrsalesdev.azurecr.io/myapi:1.0 --registry-server acrsalesdev.azurecr.io \
--target-port 8000 --ingress external --min-replicas 0 --max-replicas 3 \
--env-vars APP_ENV=prod
az containerapp show -n sales-api -g rg-demo --query properties.configuration.ingress.fqdn -o tsv # URL
az containerapp logs show -n sales-api -g rg-demo --follow
az containerapp update -n sales-api -g rg-demo --image acrsalesdev.azurecr.io/myapi:1.1 # deploy new version
az containerapp revision list -n sales-api -g rg-demo -o table
# Secrets -> environment variables
az containerapp secret set -n sales-api -g rg-demo --secrets api-key=<value>
az containerapp update -n sales-api -g rg-demo --set-env-vars API_KEY=secretref:api-key
10. App Service (Web Apps)¶
Managed hosting for web apps from code or containers (PaaS). An App Service plan (the server size) hosts one or more web apps; deploy code, Azure runs it.
Use it for classic web apps / APIs where you deploy code without a Dockerfile, with deployment slots, custom domains and always-on.
# Quickest: from the project folder
az webapp up -n sales-web -g rg-demo --runtime "PYTHON:3.12" --sku B1
# Step by step
az appservice plan create -n plan-demo -g rg-demo --is-linux --sku B1
az webapp create -n sales-web -g rg-demo -p plan-demo --runtime "PYTHON:3.12"
az webapp config appsettings set -n sales-web -g rg-demo --settings APP_ENV=prod API_KEY=@Microsoft.KeyVault(SecretUri=<uri>)
az webapp config set -n sales-web -g rg-demo \
--startup-file "gunicorn -w 2 -k uvicorn.workers.UvicornWorker app.main:app" # FastAPI
az webapp deploy -n sales-web -g rg-demo --src-path app.zip --type zip
az webapp log tail -n sales-web -g rg-demo
az webapp browse -n sales-web -g rg-demo
App settings become environment variables inside the app. F1 free tier exists but sleeps and has limits.
11. Azure Functions¶
Serverless functions triggered by HTTP, timers, queues or blob uploads; pay per execution. Write small functions locally with Core Tools, then publish to a Function App.
Use it for scheduled jobs (nightly data pull), reacting to file uploads, small webhooks.
npm install -g azure-functions-core-tools@4 # or: winget install Microsoft.Azure.FunctionsCoreTools
func init myfunc --python
cd myfunc
func new --name hello --template "HTTP trigger"
func start # run locally
az functionapp create -n fn-sales-dev -g rg-demo --storage-account stsalesdev123 \
--consumption-plan-location swedencentral --runtime python --runtime-version 3.11 \
--functions-version 4 --os-type linux
func azure functionapp publish fn-sales-dev
12. Key Vault (Secrets)¶
Secure storage for secrets (API keys, passwords), keys and certificates. Store secrets once; apps read them at runtime with their managed identity; access controlled by RBAC and logged.
Use it in every secret in production, instead of
.envfiles or hard-coded values.
az keyvault create -n kv-sales-dev -g rg-demo -l swedencentral # RBAC authorization is the default
az role assignment create --assignee $(az ad signed-in-user show --query id -o tsv) \
--role "Key Vault Secrets Officer" \
--scope $(az keyvault show -n kv-sales-dev --query id -o tsv)
az keyvault secret set --vault-name kv-sales-dev -n openai-key --value "<secret>"
az keyvault secret show --vault-name kv-sales-dev -n openai-key --query value -o tsv
az keyvault secret list --vault-name kv-sales-dev -o table
az keyvault secret delete --vault-name kv-sales-dev -n openai-key # soft-deleted, recoverable
Key Vault names are globally unique (3 to 24 characters). Soft delete keeps deleted vaults / secrets for a retention period; purge removes them for good.
13. Databases¶
Managed databases: PostgreSQL, MySQL, Azure SQL, Cosmos DB. Azure runs the server (backups, patching, HA); you connect with normal tools (psql, SQLAlchemy).
Use it for app data that must persist. SQL basics: 20 - SQL.
# PostgreSQL Flexible Server (password from an environment variable, not typed in the command)
az postgres flexible-server create -n pg-sales-dev -g rg-demo -l swedencentral \
--tier Burstable --sku-name Standard_B1ms --storage-size 32 --version 16 \
--admin-user pgadmin --admin-password "$PG_PASSWORD" \
--public-access $(curl -s https://api.ipify.org)
az postgres flexible-server firewall-rule create -n pg-sales-dev -g rg-demo \
--rule-name my-ip --start-ip-address <ip> --end-ip-address <ip>
az postgres flexible-server db create -s pg-sales-dev -g rg-demo -d salesdb
az postgres flexible-server stop -n pg-sales-dev -g rg-demo # save cost when not used
psql "host=pg-sales-dev.postgres.database.azure.com port=5432 dbname=salesdb user=pgadmin sslmode=require"
| Service | Use for |
|---|---|
| Azure Database for PostgreSQL / MySQL | Open-source relational databases |
| Azure SQL Database | Microsoft SQL Server, serverless option |
| Cosmos DB | Global NoSQL (JSON documents), also vector search |
14. Networking¶
Virtual networks, subnets, firewalls and IP addresses. A VNet is your private network; NSGs filter traffic; resources get private and optionally public IPs.
Use it for securing VMs and databases, connecting services privately, opening ports.
az network vnet create -g rg-demo -n vnet-demo --address-prefix 10.0.0.0/16 \
--subnet-name default --subnet-prefix 10.0.0.0/24
az network vnet list -o table
az network nsg list -o table
az network nsg rule list -g rg-demo --nsg-name myvmNSG -o table
az network public-ip list -o table
az vm open-port -g rg-demo -n myvm --port 80 --priority 900 # opens to the internet: web servers only
Never open SSH (22), RDP (3389) or database ports to *. Limit to your IP (see 49 - Azure VM) or use Azure Bastion / private endpoints.
15. Identity and Access (RBAC)¶
Controlling who can do what on which resources. A role assignment = who (user, group, identity) + role (set of permissions) + scope (subscription, RG or resource).
Use it for giving a teammate access, letting an app read storage, fixing "AuthorizationFailed".
| Role | Can |
|---|---|
| Owner | Everything, including granting access |
| Contributor | Create / change / delete resources, not grant access |
| Reader | View only |
| Storage Blob Data Contributor / Reader | Read / write blob data |
| Key Vault Secrets User / Officer | Read / manage secrets |
| AcrPull / AcrPush | Pull / push container images |
az role assignment create --assignee user@example.com --role Reader \
--scope /subscriptions/<sub-id>/resourceGroups/rg-demo
az role assignment list --assignee user@example.com --all -o table
az role assignment delete --assignee user@example.com --role Reader -g rg-demo
az role definition list --query "[?contains(roleName, 'Storage')].roleName" -o tsv
Give the smallest role on the smallest scope that works (least privilege).
16. Managed Identity and Service Principals¶
Identities for apps and automation instead of personal accounts or stored passwords. Managed identity: Azure creates and rotates credentials for a resource. Service principal: an app identity with a secret or certificate, for outside Azure (CI).
Use it for an app in Azure accessing storage / Key Vault (managed identity); GitHub Actions deploying to Azure (service principal / federated credential).
# Managed identity for a container app, then allow it to read secrets
az containerapp identity assign -n sales-api -g rg-demo --system-assigned
PRINCIPAL=$(az containerapp show -n sales-api -g rg-demo --query identity.principalId -o tsv)
az role assignment create --assignee $PRINCIPAL --role "Key Vault Secrets User" \
--scope $(az keyvault show -n kv-sales-dev --query id -o tsv)
# Service principal for CI (prints a secret once: store it in GitHub secrets, never in code)
az ad sp create-for-rbac --name sp-sales-ci --role Contributor \
--scopes /subscriptions/<sub-id>/resourceGroups/rg-demo
17. Azure SDK for Python¶
Python libraries to use Azure services from code.
DefaultAzureCredentialtries youraz loginlocally and the managed identity in Azure, so the same code works in both.Use it for reading blobs, secrets or databases from a Python app or notebook.
from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient
from azure.storage.blob import BlobServiceClient
credential = DefaultAzureCredential() # az login locally, managed identity in Azure
secrets = SecretClient("https://kv-sales-dev.vault.azure.net", credential)
api_key = secrets.get_secret("openai-key").value
blobs = BlobServiceClient("https://stsalesdev123.blob.core.windows.net", credential)
data = blobs.get_blob_client("data", "sales.csv").download_blob().readall()
18. Azure OpenAI¶
OpenAI models (GPT family, embeddings) hosted in Azure, with Azure security and regions. Create an Azure OpenAI resource, deploy a model under a deployment name, call it with the
openaiPython package.Use it for LLM features where data must stay in Azure / EU, or enterprise requirements. For self-hosted open models, see 49 - Azure VM + Ollama.
az cognitiveservices account create -n aoai-sales -g rg-demo -l swedencentral --kind OpenAI --sku S0
az cognitiveservices account list-models -n aoai-sales -g rg-demo -o table # what you can deploy
az cognitiveservices account deployment create -n aoai-sales -g rg-demo \
--deployment-name chat --model-name <model> --model-version <version> \
--model-format OpenAI --sku-name GlobalStandard --sku-capacity 10
az cognitiveservices account show -n aoai-sales -g rg-demo --query properties.endpoint -o tsv
import os
from openai import AzureOpenAI
client = AzureOpenAI(
azure_endpoint=os.environ["AZURE_OPENAI_ENDPOINT"],
api_key=os.environ["AZURE_OPENAI_API_KEY"],
api_version="2024-10-21",
)
resp = client.chat.completions.create(
model="chat", # the DEPLOYMENT name, not the model name
messages=[{"role": "user", "content": "Summarise Azure in one sentence."}],
)
print(resp.choices[0].message.content)
Model names, versions and API versions change often: check list-models and the Azure docs. Azure AI Foundry (portal) offers more models from other providers.
19. Monitoring and Logs¶
Seeing what happened (activity log), how resources perform (metrics) and what apps log. Activity log records management actions; Azure Monitor collects metrics; Application Insights / Log Analytics store app logs and traces.
Use it to answer questions like "Who deleted this?", "why is the app slow?", debugging production errors.
az monitor activity-log list -g rg-demo --offset 1d -o table # who did what, last day
az monitor metrics list --resource $(az vm show -g rg-demo -n myvm --query id -o tsv) \
--metric "Percentage CPU" --interval PT5M -o table
az containerapp logs show -n sales-api -g rg-demo --follow # app logs
az webapp log tail -n sales-web -g rg-demo
Python app telemetry to Application Insights:
from azure.monitor.opentelemetry import configure_azure_monitor
configure_azure_monitor() # reads APPLICATIONINSIGHTS_CONNECTION_STRING from the environment
20. Cost Management¶
Tracking and limiting what you spend. Cost Management in the Portal shows spend per resource / RG; budgets send alerts; stop or delete idle resources.
Use it for from day one; cloud bills grow quietly.
- Portal -> Cost Management -> Cost analysis (group by resource group) and Budgets (alert at 50%, 80%, 100%).
- Use the Pricing calculator (azure.microsoft.com/pricing/calculator) before creating big resources.
az consumption budget create --budget-name monthly-50 --amount 50 --category Cost \
--time-grain Monthly --start-date 2026-10-01 --end-date 2027-09-30
az vm deallocate -g rg-demo -n myvm # stop VM compute billing
az vm auto-shutdown -g rg-demo -n myvm --time 1900
az postgres flexible-server stop -n pg-sales-dev -g rg-demo
az containerapp update -n sales-api -g rg-demo --min-replicas 0 # scale to zero when idle
az group delete -n rg-demo --yes # the only way to be sure nothing is left
| Cost trap | Fix |
|---|---|
| VM "stopped" but still billed | deallocate, not stop |
| Disks, public IPs, snapshots left after deleting a VM | Delete the resource group |
| Premium SKUs chosen by default | Pick Basic / Burstable for dev |
| Log Analytics ingesting too much | Lower log level, set daily cap |
21. Tags, Locks and Cleanup¶
Labels for organising / billing, and locks that prevent accidental deletion. Tags are key=value pairs on resources; locks block delete (or all changes) until removed.
Use it for tags on everything (owner, env, project); locks on production resources.
az group update -n rg-demo --tags env=dev owner=harman project=sales
az resource list --tag env=dev -o table
az resource tag --tags env=dev --ids <resource-id>
az lock create -n no-delete --lock-type CanNotDelete -g rg-prod
az lock list -g rg-prod -o table
az lock delete -n no-delete -g rg-prod
az group list --query "[?tags.env=='dev'].name" -o tsv # find dev groups to clean up
22. Infrastructure as Code (Bicep)¶
Describing Azure resources in files instead of clicking or running many commands. Bicep files declare resources;
az deployment group createmakes Azure match the file (repeatable, reviewable in Git).Use it for anything you will create more than once (dev / test / prod), or want to review in pull requests.
// main.bicep
param location string = resourceGroup().location
param storageName string
resource storage 'Microsoft.Storage/storageAccounts@2023-05-01' = {
name: storageName
location: location
sku: { name: 'Standard_LRS' }
kind: 'StorageV2'
properties: { minimumTlsVersion: 'TLS1_2' }
}
output blobEndpoint string = storage.properties.primaryEndpoints.blob
az bicep install
az deployment group what-if -g rg-demo --template-file main.bicep --parameters storageName=stdemo123 # preview
az deployment group create -g rg-demo --template-file main.bicep --parameters storageName=stdemo123
az deployment group list -g rg-demo -o table
Terraform is a popular multi-cloud alternative; the Azure Developer CLI (azd up) deploys full app templates.
23. End to End: Deploy a FastAPI Container¶
The full path from local FastAPI project to a public HTTPS API. Resource group -> registry build -> container app -> test URL -> clean up.
Use it for shipping an API from 40 - FastAPI with the Dockerfile from 43 - Docker.
RG=rg-sales-api; LOC=swedencentral; ACR=acrsalesapi$RANDOM; APP=sales-api
az group create -n $RG -l $LOC
az acr create -g $RG -n $ACR --sku Basic --admin-enabled true
az acr build -r $ACR -t $APP:1.0 . # build image in Azure
az containerapp env create -n cae-$APP -g $RG -l $LOC
az containerapp create -n $APP -g $RG --environment cae-$APP \
--image $ACR.azurecr.io/$APP:1.0 --registry-server $ACR.azurecr.io \
--target-port 8000 --ingress external --min-replicas 0 --max-replicas 2
URL=$(az containerapp show -n $APP -g $RG --query properties.configuration.ingress.fqdn -o tsv)
curl https://$URL/ # test
echo "Docs: https://$URL/docs"
# New version
az acr build -r $ACR -t $APP:1.1 .
az containerapp update -n $APP -g $RG --image $ACR.azurecr.io/$APP:1.1
az group delete -n $RG --yes --no-wait # clean up everything
For production, prefer a managed identity with the AcrPull role over registry admin credentials.
24. Which Service to Use¶
A quick mapping from need to Azure service. Start with the most managed option; go lower (VMs) only when you need the control.
Use it for planning where to run a project.
| Need | Service |
|---|---|
| Run a container / API with HTTPS and autoscale | Container Apps |
| Host a web app from code (no Dockerfile) | App Service |
| Scheduled or event-triggered small jobs | Azure Functions (or Container Apps jobs) |
| Full OS control, GPU, custom software | Virtual Machines |
| Many containers, complex orchestration | AKS (Kubernetes) |
| Files, datasets, model files | Blob Storage |
| Relational database | PostgreSQL Flexible Server / Azure SQL |
| NoSQL / global JSON data | Cosmos DB |
| Secrets and keys | Key Vault |
| Container images | Container Registry |
| LLM APIs (GPT) | Azure OpenAI / AI Foundry |
| Search / RAG index | Azure AI Search |
| Big data / notebooks | Databricks, Microsoft Fabric |
| ML training and model registry | Azure Machine Learning |
25. Naming Conventions¶
A consistent pattern for resource names.
<type prefix>-<app>-<env>[-<region>]; some types forbid dashes.Use it in every resource; makes costs, logs and cleanup easy to follow.
| Resource | Prefix | Example |
|---|---|---|
| Resource group | rg- |
rg-sales-dev |
| Virtual machine | vm- |
vm-ollama-dev |
| Storage account | st (no dashes, lowercase) |
stsalesdev001 |
| Container registry | acr (no dashes) |
acrsalesdev |
| Container app / environment | ca- / cae- |
ca-sales-api, cae-sales-dev |
| App Service plan / web app | asp- / app- |
asp-sales-dev, app-sales-dev |
| Key Vault | kv- |
kv-sales-dev |
| PostgreSQL | psql- |
psql-sales-dev |
| Virtual network / NSG | vnet- / nsg- |
vnet-sales-dev, nsg-vm-ollama |
26. Troubleshooting¶
| Error / problem | Fix |
|---|---|
Please run 'az login' to setup account |
az login (or --use-device-code on a VM) |
| Resources not found / wrong list | Wrong subscription: az account show, then az account set |
The subscription is not registered to use namespace 'Microsoft.X' |
az provider register -n Microsoft.X |
QuotaExceeded / OperationNotAllowed for VM size |
az vm list-usage -l <region>; pick another size / region or request a quota increase |
SkuNotAvailable / region not accepting customers |
Try another region (swedencentral, northeurope, francecentral) |
AuthorizationFailed |
Missing role on that scope; ask an Owner for a role assignment |
Storage / Key Vault 403 with --auth-mode login |
Assign the data role (Storage Blob Data Contributor, Key Vault Secrets User); wait a few minutes |
The storage account name is already taken |
Names are global; add digits / initials |
| Container app shows default page or 404 | Wrong --target-port, or the app listens on 127.0.0.1 instead of 0.0.0.0 |
| Container app cannot pull image | Pass --registry-server (+ identity with AcrPull, or admin credentials) |
az containerapp not recognized |
az extension add --name containerapp --upgrade |
| Unexpected bill | Cost analysis by resource group; deallocate VMs, delete unused RGs, set a budget |
| Command hangs or unclear error | Re-run with --debug; check the Activity log in the Portal |
27. Try It¶
Short exercises to practise this guide. Try each task yourself first, then open the solution.
Use it right after reading the guide, or later as a quick self-test.
Exercise 1: Inventory¶
List all resources of a resource group as a table with only name and type.
Exercise 2: Secret round trip¶
Store a secret in Key Vault and read only its value.
Solution
Exercise 3: Deploy the capstone¶
Deploy the chatbot container to Azure Container Apps and delete everything afterwards.
Solution
Follow 97 - Capstone Project section 13, then az group delete -n rg-docs-chatbot --yes --no-wait.
Previous: 47 - Terraform | Index: All guides | Next: 49 - Azure VM + Linux + Ollama