Chapter 8
Containers, App Service & Functions
Not everything needs a VM. This chapter covers the platform services that run your code or containers for you: Container Registry, Container Instances, Container Apps, App Service and Azure Functions. It ends with a decision guide for choosing a hosting option and a short tour of Azure's AI, machine learning and IoT services. In the lab you run the same image in all of them, and connect the web app to snet-app from chapter 4.
Theory
Azure Container Registry
A container image is a packaged app with everything it needs to run. Images are stored in a registry; Azure Container Registry (ACR) is your private one, at <name>.azurecr.io. Inside it, images are grouped in repositories and identified by tags, like aci-helloworld:v1.
| SKU | Adds |
|---|---|
| Basic | Cheapest, for learning and small teams. Lower storage and throughput. |
| Standard | More storage and throughput. Most production use. |
| Premium | Geo-replication (one registry in several regions), private endpoints, content trust, highest throughput. |
Ways to authenticate to ACR, from best to worst:
- Managed identity with the AcrPull role: the recommended way for Container Apps, App Service, AKS and ACI to pull images.
- Individual Entra login:
az acr login, for people. - Service principal with AcrPull/AcrPush, for CI/CD pipelines.
- Repository-scoped tokens: limited to certain repositories.
- Admin user: one username and two passwords with full push/pull rights. Disabled by default; only for testing.
Useful features: ACR Tasks build images in Azure (az acr build, no local Docker needed) and can rebuild automatically when a base image changes. az acr import copies an image from another registry without pulling it to your machine.
Azure Container Instances
Azure Container Instances (ACI) is the simplest way to run a container: no VMs, no orchestrator, pay per second. The unit of deployment is a container group: one or more containers that are scheduled on the same host and share a lifecycle, IP address, network and storage volumes (similar to a Kubernetes pod).
- Linux or Windows containers. Multi-container groups are Linux only.
- Networking: a public IP with an optional DNS name label (
<label>.<region>.azurecontainer.io), or deploy into a delegated subnet of your VNet for private access. - Restart policy: Always (default, for long-running services), OnFailure or Never (for run-once tasks and batch jobs).
- Volumes: mount an Azure Files share, a secret, an emptyDir or a git repo.
- Sizing: you request CPU and memory per container when you create the group. To change them you redeploy the group.
- No autoscaling. To handle more load you create more container groups yourself (or use Container Apps).
Azure Container Apps
Azure Container Apps (ACA) runs containers on a managed Kubernetes platform without exposing Kubernetes. It adds what ACI lacks: autoscaling (including to zero), HTTPS ingress, revisions and traffic splitting.
- Environment: a secure boundary around a group of container apps. Apps in one environment share a VNet and a Log Analytics workspace. Workload profiles are Consumption (serverless, pay per use) or Dedicated (reserved hardware, e.g. for GPUs or more memory).
- Ingress: external (internet) or internal (environment/VNet only), with a free HTTPS endpoint.
- Revisions: every change to the container template creates an immutable revision. In multiple revision mode you can split traffic, e.g. 90% to v1 and 10% to v2.
- Sizing: CPU and memory per container in fixed combinations, such as 0.25 vCPU / 0.5 GiB up to 4 vCPU / 8 GiB on Consumption.
Scaling in Container Apps
You set min replicas and max replicas and one or more scale rules. Scaling is driven by KEDA:
- HTTP: number of concurrent requests per replica (default 10).
- TCP: number of concurrent connections.
- Custom (KEDA scalers): queue length in Service Bus or Storage queues, Event Hubs lag, Kafka, and many more.
- CPU / memory utilisation (these can't scale to zero).
With min replicas = 0 the app scales to zero when idle, so you pay nothing for compute, at the cost of a cold start on the first request.
Which container service?
| ACI | Container Apps | AKS | App Service (containers) | |
|---|---|---|---|---|
| Best for | Simple, short-lived or batch containers | Microservices, APIs, event-driven apps | Full Kubernetes control | Web apps and APIs |
| Autoscale | No | Yes, incl. to zero | Yes (you configure) | Yes (plan level) |
| Kubernetes API | No | No | Yes | No |
| You manage | Almost nothing | Almost nothing | Cluster, upgrades, node pools | The plan |
Azure App Service
App Service hosts web apps, REST APIs and mobile back ends as code (.NET, Java, Node.js, Python, PHP) or as a container, on Windows or Linux. Microsoft patches the OS and runtime; you deploy your app.
App Service plans
Every app runs in an App Service plan, which defines the region, OS, pricing tier and number of instances. All apps in a plan share those instances: three apps on one plan with two instances means all three apps run on both instances. You pay for the plan, not per app.
| Tier | Max instances | Autoscale | Slots | Notable |
|---|---|---|---|---|
| Free (F1) / Shared (D1) | 1 (shared hardware) | No | β | Dev/test only, CPU minutes per day, no TLS for custom domains |
| Basic (B1βB3) | 3 | No, manual only | β | Custom domains + TLS, VNet integration, dedicated VMs |
| Standard (S1βS3) | 10 | Yes | 5 | The minimum for autoscale and slots |
| Premium v3 / v4 | 30 | Yes, plus automatic scaling | 20 | Zone redundancy, faster hardware |
| Isolated v2 | 100 | Yes | 20 | Runs in an App Service Environment (single tenant, in your VNet) |
Two ways to scale:
- Scale up: change the tier/size (more CPU, memory, features). Apps restart.
- Scale out: change the number of instances, manually or with autoscale rules (metric- or schedule-based, Standard+, just like scale sets in chapter 5). Premium also offers automatic scaling, where the platform scales on HTTP load by itself.
"Choose the cheapest tier that supports deployment slots / autoscale." Answer: Standard. "β¦that supports custom domains with TLS / VNet integration": Basic. "β¦zone redundancy": Premium v3.
Deployment slots
A deployment slot is a live copy of your app with its own hostname, like app-az104-xx-staging.azurewebsites.net. The typical flow:
- Deploy the new version to the staging slot and test it there.
- Swap staging with production. Azure first warms up the staging instances, then switches the routing, so there's no downtime and no cold start.
- If something's wrong, swap back: the previous version is now in the staging slot.
- Swapped: app settings and connection strings (unless sticky), general settings, handler mappings, the code itself.
- Not swapped: settings marked as deployment slot setting, custom domains, TLS bindings, scale settings, VNet integration, managed identities, IP restrictions.
- Swap with preview applies the production settings to staging first, so you can test before completing the swap.
- Auto swap swaps automatically after each deployment to a slot.
- Traffic routing can send a percentage of production traffic to a slot ("testing in production").
Custom domains and TLS
Every app gets <app>.azurewebsites.net with HTTPS. To use your own name:
- Prove ownership with a TXT record
asuid.<subdomain>containing the app's custom domain verification ID. - Point the name at the app: a CNAME to
<app>.azurewebsites.netfor a subdomain likewww, or an A record to the app's IP for the apex domain. - Add the domain in the app (Custom domains), then add a TLS/SSL binding.
Certificate options: the free App Service managed certificate (auto-renewed; no wildcards, not exportable), a certificate imported from Key Vault, an uploaded .pfx, or an App Service certificate you buy. Bindings use SNI SSL (normal) or IP-based SSL. Also set HTTPS Only and a minimum TLS version (1.2 or 1.3).
Backup
App Service can back up the app's content, configuration and (optionally) a linked database:
- Automatic backups: taken by the platform every hour on Basic tier and higher, kept for 30 days, no storage account needed.
- Custom backups: on a schedule you define, to a storage account container you choose, with your own retention. Maximum total size 10 GB (including the database).
You can restore a backup to the same app, another app, or a slot.
Networking
App Service networking is split into inbound (clients reaching the app) and outbound (the app reaching other things). This split is a classic exam question:
| Direction | Feature | What it does |
|---|---|---|
| Inbound | Access restrictions | Allow/deny rules by IP range, service endpoint (subnet), service tag or X-Forwarded-* headers (e.g. only via Front Door). |
| Private endpoint | Gives the app a private IP in your VNet, so clients reach it privately. Public access can then be disabled. | |
| Outbound | VNet integration | The app can call resources in or through your VNet (VMs, private endpoints, on-prem via VPN). Needs an empty, delegated subnet. With Route All, all outbound traffic goes through the VNet (so NSGs and UDRs apply). |
| Hybrid Connections | Reach a specific host:port on-premises through a relay agent, without a VPN. |
"The web app must connect to a SQL VM in a VNet." That's outbound: VNet integration. "Only users on the corporate VNet may open the web app." That's inbound: private endpoint (or access restrictions). VNet integration does not make the app private.
Azure Functions
Azure Functions runs small pieces of code (functions) in response to events, without you managing servers. This is serverless compute: on the right plan you pay only while your code runs, and the platform scales out by itself when many events arrive.
Every function has exactly one trigger and any number of bindings:
- Trigger: what starts the function. Common ones: HTTP request, Timer (a CRON schedule), a new blob, a queue or Service Bus message, an Event Grid or Event Hubs event, a Cosmos DB change.
- Bindings: declarative connections to data. An input binding reads data for you (e.g. a table row), an output binding writes the result (e.g. a queue message or a blob), so you don't write SDK connection code.
Functions are written in C#, JavaScript/TypeScript, Python, Java or PowerShell, and they live in a function app: the unit of deployment and scaling, with its own settings and a required storage account for its internal state.
Hosting plans
| Plan | Scale to zero | Cold start | VNet integration | Choose it when |
|---|---|---|---|---|
| Flex Consumption | Yes | Possible; avoid with always-ready instances | Yes | The default for new serverless apps: pay per execution, fast scale-out, private networking |
| Consumption (legacy) | Yes | Yes | No | Existing apps; runs time out after 10 minutes at most |
| Premium (Elastic Premium) | No (min 1 instance) | No (pre-warmed instances) | Yes | Always-warm, long-running or heavy functions |
| Dedicated (App Service plan) | No | No (with Always On) | Yes | You already pay for an App Service plan with spare capacity |
| Container Apps | Yes | Yes | Yes | Functions packaged as containers next to other container apps |
Functions are stateless by default. For workflows with state (call A, then B, wait for a human approval, fan out to 100 parallel tasks and collect the results) you use Durable Functions, an extension that saves progress for you. If the workflow is mostly about connecting services rather than custom code, Azure Logic Apps does the same with a visual designer and hundreds of ready-made connectors.
"Run code every time a file lands in a blob container, pay nothing when no files arrive." That's Functions with a blob or Event Grid trigger on Flex Consumption. Add "without cold starts": Premium (or Flex Consumption with always-ready instances). A WebJob or a VM would both cost money while idle.
Choosing an application hosting option
You've now seen every way Azure can run your code. Exam and real-world questions boil down to how much control you need versus how much you want to manage:
| If the requirement says⦠| Choose |
|---|---|
| Full control of the OS, custom drivers, lift-and-shift of an existing server | Virtual machine (or VMSS to scale) |
| Windows desktops or apps for users, multi-session | Azure Virtual Desktop (chapter 5) |
| Web app or API in .NET/Java/Node/Python/PHP, slots, minimal management | App Service |
| Containerised microservices, scale to zero, no Kubernetes to manage | Container Apps |
| Need the Kubernetes API, Helm charts, custom operators | AKS |
| Run one container on demand or as a batch job | ACI (or a Container Apps job) |
| Short, event-driven code, pay per execution | Functions |
| Integrate SaaS and Azure services with little code | Logic Apps |
AI, machine learning and IoT services
These aren't on the AZ-104 exam, but AZ-305 expects you to know which category of service fits a requirement. Product names in this area change often; the categories don't.
AI and machine learning
- Microsoft Foundry (formerly Azure AI Foundry): the platform for building generative AI apps and agents. It gives access to large language models (including OpenAI models, through what used to be Azure OpenAI) plus tools for prompts, evaluation, safety and deployment.
- Pre-built AI services (formerly Azure AI services / Cognitive Services): ready-made models behind an API, no data science needed. Examples: Vision (image analysis, OCR), Speech (speech-to-text, text-to-speech), Language (sentiment, key phrases, PII detection), Translator, Document Intelligence (extract fields from invoices and forms) and Content Safety.
- Azure AI Search: full-text and vector search over your own data, the usual retrieval layer behind "chat with our documents" (RAG) solutions.
- Azure Machine Learning: for data scientists who train, track and deploy their own models, with MLOps pipelines, compute clusters and a model registry.
Rule of thumb: use a pre-built service if one does the job, use Foundry to build with generative models, and only train your own model in Azure Machine Learning when nothing ready-made fits your data.
IoT and edge
- Azure IoT Hub: the cloud gateway for devices. Secure per-device identity, two-way messaging (telemetry in, commands out) for millions of devices, and routing of messages to storage, Event Hubs or Functions.
- Azure IoT Edge: runs cloud workloads (containers, AI models) on the device or a local gateway, managed from IoT Hub, for low latency or intermittent connectivity.
- Azure IoT Operations: a newer, Arc-enabled platform for industrial sites that collects and processes data on a local Kubernetes cluster.
- Azure Digital Twins: a live model of a building, factory or other environment, fed by device data.
- Azure Arc: manages servers, Kubernetes clusters and databases outside Azure (on-premises, other clouds, edge) as if they were Azure resources, so Policy, RBAC, Monitor and Defender work on them. Azure Local (formerly Azure Stack HCI) runs Azure-managed VMs and AKS on your own hardware.
"Extract the total amount and invoice number from scanned invoices" β Document Intelligence, not a custom model in Azure Machine Learning. "Apply Azure Policy to on-premises Linux servers" β Azure Arc. "Send commands to 50,000 field devices and receive their telemetry" β IoT Hub.
AZ-305's "design compute" area is mostly the decision table in this chapter: App Service vs Container Apps vs AKS vs Functions vs VMs, driven by requirements like "scale to zero", "Kubernetes API needed", "minimal management", or "full OS control". Add the networking split (inbound private endpoint, outbound VNet integration) and you can answer most of them.
- Introduction to Azure Container Registry
- Authenticate with ACR
- What is Azure Container Instances?
- Container groups in ACI
- Azure Container Apps overview
- Scaling in Azure Container Apps
- App Service plans
- Set up staging slots
- Map a custom DNS name
- Secure a custom domain with a TLS binding
- Back up and restore an app
- App Service networking features
- Azure Functions overview
- Functions triggers and bindings
- Functions hosting options
- What are Durable Functions?
- Choose an Azure compute service (decision tree)
- What is Azure Machine Learning?
- IoT concepts and Azure IoT Hub
- Azure Arc overview
Self-check
1. A container must run once every night for 10 minutes to process files, and then stop. Cheapest simple option?
D. Pay per second, no idle cost. (A Container Apps job would also work.)
2. An API must scale out with HTTP load and cost nothing when unused. Which service?
B. Only Container Apps scales to zero here.
3. After a slot swap, production uses the staging database. You wanted each slot to keep its own connection string. What should you have done?
A. Sticky settings stay with the slot.
4. Your web app on a Basic plan needs a staging slot. What do you do?
C. Slots start at Standard.
5. You need the free App Service managed certificate for *.contoso.com. Will that work?
B. Use a Key Vault/App Service certificate or upload a wildcard .pfx.
6. A function must process every new message in a storage queue, must reach a database through a private endpoint, and should cost nothing when the queue is empty. Which hosting plan?
C. Flex Consumption scales to zero and supports VNet integration. Legacy Consumption has no VNet integration; Premium and Dedicated always cost money.
7. An order workflow must call three services in sequence, wait up to two days for a manager's approval, then continue. It's written in C#. What fits best?
B. Durable Functions keeps the workflow's state while it waits. (Logic Apps would also work if low-code is preferred.)
8. A company wants to read text from photos of shipping labels with as little effort as possible. Which service?
A. Pre-built AI services need no training. Only build your own model when nothing ready-made fits.
Lab: one image, four ways to run it
You put an image in your own registry, run it in ACI and Container Apps, and deploy a web app with a staging slot that's connected to snet-app.
The variables from chapter 0 ($RG, $LOC, $LOC2, $INIT, $ST, $ACR, $MYIP) load automatically in every terminal; if they don't, run . ~/az104.env. Any other variable a task needs is set at the top of that task's Azure CLI solution, so every solution works on its own in a fresh terminal.
-
Task
Create a registry and get an image into it
Create a Basic container registry
acraz104xx. Copy the public imagemcr.microsoft.com/azuredocs/aci-helloworld:latestinto it asaci-helloworld:v1, without using Docker on your machine.Done when- The registry's Repositories show
aci-helloworldwith tagv1.
Hint
There's an
az acrcommand that imports images straight from another registry.Solution Β· Portal + CLI
Create a resource β Container Registry: name
acraz104xx, SKU Basic. The import itself is CLI only (see below).Solution Β· Azure CLI
az acr create -g $RG -n $ACR -l $LOC --sku Basic az acr import -n $ACR --source mcr.microsoft.com/azuredocs/aci-helloworld:latest --image aci-helloworld:v1 az acr repository show-tags -n $ACR --repository aci-helloworld -o table - The registry's Repositories show
-
Task
Run it in Container Instances
Run your image from your registry in ACI as
aci-hello, reachable on port 80 at a public nameaci-hello-xx.<region>.azurecontainer.io, with 1 vCPU and 1 GiB memory. For pulling from ACR you may use the registry's admin user this time.Done when- The FQDN shows the "Welcome to Azure Container Instances!" page.
- You know how you'd give it 2 vCPUs. (Can you change it in place?)
Solution Β· Portal
- Registry β Settings β Access keys β enable Admin user.
- Create a resource β Container Instances: name
aci-hello, image source Azure Container Registry, registry/image/tag, size 1 vCPU, 1 GiB. - Networking: Public, DNS name label
aci-hello-xx, port 80 TCP. Restart policy On failure (Advanced tab) or leave Always. - Open the FQDN from Overview. To get 2 vCPUs you delete and recreate the container group.
Solution Β· Azure CLI
az acr update -n $ACR --admin-enabled true PW=$(az acr credential show -n $ACR --query "passwords[0].value" -o tsv) az container create -g $RG -n aci-hello -l $LOC --image $ACR.azurecr.io/aci-helloworld:v1 \ --registry-login-server $ACR.azurecr.io --registry-username $ACR --registry-password $PW \ --cpu 1 --memory 1 --ports 80 --ip-address Public --dns-name-label aci-hello-$INIT --os-type Linux az container show -g $RG -n aci-hello --query ipAddress.fqdn -o tsvCostACI bills per second while running. Delete
aci-helloafter you've seen it:az container delete -g $RG -n aci-hello -y. -
Task
Run it in Container Apps, scaling to zero
Create a Container Apps environment
cae-az104(Consumption) that sends its logs to your existing Log Analytics workspacelog-az104from chapter 4. In it, createca-hellofrom your ACR image with:- external ingress on target port 80;
- 0.25 vCPU / 0.5 GiB;
- 0 to 5 replicas, scaling on 20 concurrent HTTP requests per replica.
Then generate some load and watch the replica count.
Done when- The app URL (
https://ca-hello.β¦.azurecontainerapps.io) shows the hello page. - The Replica Count metric goes up under load and back to 0 after a few idle minutes.
Solution Β· Portal
- Create a resource β Container App: name
ca-hello, create new environmentcae-az104(Consumption only; Monitoring tab: Log Analytics βlog-az104). - Container: image source Azure Container Registry, your image, CPU/memory 0.25 / 0.5Gi.
- Ingress: enabled, Accepting traffic from anywhere, target port 80.
- After creation: Application β Scale (or Scale and replicas) β min 0, max 5, add rule HTTP scaling with concurrent requests 20 β Save (creates a new revision).
- Monitoring β Metrics β Replica Count.
Solution Β· Azure CLI
WSID=$(az monitor log-analytics workspace show -g $RG -n log-az104 --query customerId -o tsv) WSKEY=$(az monitor log-analytics workspace get-shared-keys -g $RG -n log-az104 --query primarySharedKey -o tsv) az containerapp env create -g $RG -n cae-az104 -l $LOC --logs-workspace-id $WSID --logs-workspace-key $WSKEY PW=$(az acr credential show -n $ACR --query "passwords[0].value" -o tsv) az containerapp create -g $RG -n ca-hello --environment cae-az104 \ --image $ACR.azurecr.io/aci-helloworld:v1 \ --registry-server $ACR.azurecr.io --registry-username $ACR --registry-password $PW \ --target-port 80 --ingress external --cpu 0.25 --memory 0.5Gi \ --min-replicas 0 --max-replicas 5 \ --scale-rule-name http-rule --scale-rule-type http --scale-rule-http-concurrency 20 URL=https://$(az containerapp show -g $RG -n ca-hello --query properties.configuration.ingress.fqdn -o tsv) curl -s $URL | head -5 for i in $(seq 300); do curl -s -o /dev/null $URL & done; wait az containerapp replica list -g $RG -n ca-hello -o tableIn production you'd use a managed identity with AcrPull instead of the admin password (
--registry-identity system). -
Task
Create a web app that can use slots
Create a Linux App Service plan
asp-az104in the cheapest tier that supports deployment slots, and a web appapp-az104-xxrunning the containermcr.microsoft.com/azuredocs/aci-helloworld:latest. Make it HTTPS only with minimum TLS 1.2.Done whenhttps://app-az104-xx.azurewebsites.netshows the hello page (the first start can take a minute).http://redirects tohttps://.
Solution Β· Portal
- Create a resource β Web App: name
app-az104-xx, publish Container, OS Linux, region, new planasp-az104, pricing plan Standard S1. - Container tab: image source Other container registries, public, server
https://mcr.microsoft.com, imageazuredocs/aci-helloworld:latest. - After creation: Settings β Configuration β General settings: HTTPS Only On, Minimum inbound TLS 1.2.
Solution Β· Azure CLI
# Variables for this task APP=app-az104-${INIT} az appservice plan create -g $RG -n asp-az104 -l $LOC --is-linux --sku S1 az webapp create -g $RG -p asp-az104 -n $APP --container-image-name mcr.microsoft.com/azuredocs/aci-helloworld:latest az webapp update -g $RG -n $APP --https-only true az webapp config set -g $RG -n $APP --min-tls-version 1.2 curl -sI http://$APP.azurewebsites.net | head -3 -
Task
Release a new version with a slot swap
Create a staging slot that runs a different image,
mcr.microsoft.com/azuredocs/containerapps-helloworld:latest. Give both slots an app settingENV_NAME(production/staging) that must stay with its slot. Then swap staging into production.Done when- The production URL now shows the Container Apps hello page, and the staging URL shows the old one.
ENV_NAMEin production is stillproduction.
Solution Β· Portal
- Web app β Deployment β Deployment slots β Add slot: name
staging, clone settings from production. - Open the staging slot β Deployment Center: change the image to
azuredocs/containerapps-helloworld:latest, Save. - In each slot: Settings β Environment variables β App settings β Add
ENV_NAME, tick Deployment slot setting. - Deployment slots β Swap: source
staging, targetproduction. Look at the "config changes" preview, then Swap.
Solution Β· Azure CLI
# Variables for this task APP=app-az104-${INIT} az webapp deployment slot create -g $RG -n $APP --slot staging --configuration-source $APP az webapp config container set -g $RG -n $APP --slot staging \ --container-image-name mcr.microsoft.com/azuredocs/containerapps-helloworld:latest az webapp config appsettings set -g $RG -n $APP --slot-settings ENV_NAME=production az webapp config appsettings set -g $RG -n $APP --slot staging --slot-settings ENV_NAME=staging az webapp deployment slot swap -g $RG -n $APP --slot staging --target-slot production az webapp config appsettings list -g $RG -n $APP --query "[?name=='ENV_NAME']" -o table -
Task
Scale the plan
Add autoscale to
asp-az104: between 1 and 3 instances, +1 when average CPU > 70% for 10 minutes, β1 when < 30%. Then look at what would happen if you scaled up to Premium v3 (don't do it, just look at what features it lists).Done when- The plan's Scale out page shows custom autoscale with two rules.
Solution Β· Portal
asp-az104β Settings β Scale out (App Service plan) β Rules Based β Manage rules based scaling β Custom autoscale: min 1, max 3, default 1, add the scale-out and scale-in rules β Save. Scale up (App Service plan) shows the tiers and features.Solution Β· Azure CLI
az monitor autoscale create -g $RG --resource asp-az104 --resource-type Microsoft.Web/serverfarms \ -n autoscale-asp --min-count 1 --max-count 3 --count 1 az monitor autoscale rule create -g $RG --autoscale-name autoscale-asp --condition "CpuPercentage > 70 avg 10m" --scale out 1 az monitor autoscale rule create -g $RG --autoscale-name autoscale-asp --condition "CpuPercentage < 30 avg 10m" --scale in 1 -
Task
Connect the app to your network, and restrict who can reach it
- Let the web app make outbound calls into
vnet-spokethroughsnet-app(the delegated subnet you made with Bicep). - Allow inbound traffic to the production app only from your browser's public IP. Check from your Linux VM that it's blocked, then remove the restriction again.
Done when- Networking shows Virtual network integration with
snet-app. - The Linux VM gets 403 while your browser still works.
- You can explain why VNet integration didn't make the app private.
Solution Β· Portal
- Web app β Settings β Networking β Outbound traffic configuration β Virtual network integration β Add β
vnet-spoke/snet-app. - Inbound traffic configuration β Public network access β Enabled from select virtual networks and IP addresses, add an Allow rule for your browser's IP (
x.x.x.x/32), unmatched rule action Deny. Save. - On the Linux VM:
curl -s -o /dev/null -w "%{http_code}" https://app-az104-xx.azurewebsites.netβ 403. Then set public access back to Enabled with no access restrictions.
VNet integration is outbound only. Making the app private needs a private endpoint (inbound).
Solution Β· Azure CLI
# Variables for this task APP=app-az104-${INIT} az webapp vnet-integration add -g $RG -n $APP --vnet vnet-spoke --subnet snet-app az webapp access-restriction add -g $RG -n $APP --rule-name allow-me --action Allow \ --ip-address <your-browser-ip>/32 --priority 100 curl -s -o /dev/null -w "%{http_code}\n" https://$APP.azurewebsites.net # 403 from the Linux VM az webapp access-restriction remove -g $RG -n $APP --rule-name allow-me - Let the web app make outbound calls into
-
Task Β· optional, needs the chapter 3 DNS zone
Put the web app on your own domain with TLS
Make the production app reachable at
https://www.lab.yourdomain.comwith a valid certificate that costs nothing and renews itself. Create the DNS records in your Azure DNS zonelab.yourdomain.comfrom chapter 3.Done when- Your browser opens
https://www.lab.yourdomain.comwith a padlock and no certificate warning. - You can name the two DNS records you needed, and why one of them is a TXT record.
- You know whether this custom domain would move to the staging slot on the next swap.
Hint
App Service wants proof that you own the name: a TXT record
asuid.<subdomain>containing the app's custom domain verification ID. In a zone calledlab.yourdomain.com, the record names are relative, so it'sasuid.wwwandwww.Solution Β· Portal
- Web app β Settings β Custom domains β + Add custom domain: domain provider All other domain services, TLS/SSL certificate App Service Managed Certificate, TLS/SSL type SNI SSL, domain
www.lab.yourdomain.com. The wizard shows the CNAME and TXT values; keep it open. - In another tab, DNS zone
lab.yourdomain.comβ + Record set: namewww, type CNAME, aliasapp-az104-xx.azurewebsites.net. Another: nameasuid.www, type TXT, value = the verification ID. - Back in the wizard: Validate β Add. The managed certificate is created and bound automatically (a few minutes).
Custom domains and TLS bindings are not swapped: they stay with the production slot.
Solution Β· Azure CLI
# Variables for this task APP=app-az104-${INIT} ZONE=lab.yourdomain.com VID=$(az webapp show -g $RG -n $APP --query customDomainVerificationId -o tsv) az network dns record-set txt add-record -g $RG -z $ZONE -n asuid.www -v $VID az network dns record-set cname set-record -g $RG -z $ZONE -n www -c $APP.azurewebsites.net az webapp config hostname add -g $RG --webapp-name $APP --hostname www.$ZONE az webapp config ssl create -g $RG -n $APP --hostname www.$ZONE # free managed certificate THUMB=$(az webapp config ssl list -g $RG --query "[?subjectName=='www.$ZONE'].thumbprint | [0]" -o tsv) az webapp config ssl bind -g $RG -n $APP --certificate-thumbprint $THUMB --ssl-type SNI curl -sI https://www.$ZONE | head -1Also have a quick look at Settings β Backups: automatic backups are already running, and this is where you'd configure a custom backup to a storage account.
- Your browser opens
The Standard S1 plan is the most expensive thing in this lab (about β¬0.09/hour). Delete the web app and asp-az104 at the end of this chapter (later chapters don't need them), and delete aci-hello if you haven't. The Container App scales to zero and the Basic registry costs a few cents a day, so they can stay until chapter 10.
# Variables for this task
APP=app-az104-${INIT}
ZONE=lab.yourdomain.com # only if you did the custom domain task
az network dns record-set cname delete -g $RG -z $ZONE -n www --yes # if you did the custom domain task
az network dns record-set txt delete -g $RG -z $ZONE -n asuid.www --yes
az webapp delete -g $RG -n $APP
az appservice plan delete -g $RG -n asp-az104 -y
az container delete -g $RG -n aci-hello -y- Registry
acraz104xxwithaci-helloworld:v1. - Container Apps environment
cae-az104(logging tolog-az104) withca-hello, scaling 0β5. - You built and deleted ACI, an App Service plan with slots, autoscale, VNet integration and (optionally) a custom domain with a managed certificate.