Domain 1 β€” Module 4 of 8 50%
4 of 27 overall
Domain 1: Develop containerized solutions on Azure Free ⏱ ~11 min read

Containers on App Service: Env Vars and Secrets

Run a container on Azure App Service the right way. Image pull with managed identity, app settings, Key Vault references, deployment slots, and when App Service beats Container Apps for AI workloads.

When App Service is the right fit

Simple explanation

Azure App Service is the most managed way to run a container that serves HTTP traffic. You hand Azure a container image, it runs the container behind a load balancer, gives you HTTPS, deployment slots, autoscaling, and a domain β€” done.

Compared to Container Apps, App Service is older and simpler: one container per app, traditional autoscale on CPU/memory or custom rules, no scale-to-zero on Linux container plans. Compared to AKS, it hides Kubernetes entirely.

For AI-200: the exam tests how App Service supplies environment variables and secrets to your container, and how it pulls images from ACR without passwords using managed identity.

App settings β€” how App Service supplies environment variables

In App Service, app settings become environment variables inside your container at startup. Set them via portal, CLI, or ARM/Bicep:

az webapp config appsettings set \
  --name roo-inference \
  --resource-group roo-prod \
  --settings \
    LOG_LEVEL=info \
    MODEL_NAME=phi-4-mini \
    INFERENCE_BATCH_SIZE=8 \
    WEBSITES_PORT=8000

Inside the container, your code reads them with os.environ.get('MODEL_NAME') (Python), process.env.MODEL_NAME (Node.js), and so on.

SettingPurpose
WEBSITES_PORTThe port your container listens on (App Service will route traffic to it)
WEBSITES_ENABLE_APP_SERVICE_STORAGEWhether to mount the App Service file system into the container
DOCKER_REGISTRY_SERVER_URLCustom registry URL (when not using managed identity for ACR)
Anything you defineYour app’s configuration
Watch out: app settings are not encrypted at rest by default

App Service app settings are stored as part of the site configuration and are encrypted at rest, but they’re visible to anyone with Contributor on the App Service resource. Do not put long-lived passwords or API keys directly in app settings.

For secrets, use Key Vault references (next section) β€” the secret stays in Key Vault, App Service looks it up at startup, and the value never appears in app settings.

Secrets β€” Key Vault references

The recommended pattern is: secrets live in Key Vault; App Service references them by URI; the container sees only the resolved value at startup.

# Reference syntax in app settings:
DB_CONNECTION_STRING=@Microsoft.KeyVault(SecretUri=https://roo-kv.vault.azure.net/secrets/DbConnString)
OPENAI_API_KEY=@Microsoft.KeyVault(SecretUri=https://roo-kv.vault.azure.net/secrets/OpenAIKey)

Three things must be true for a Key Vault reference to resolve:

  1. App Service has a system-assigned or user-assigned managed identity enabled
  2. That identity has Get permission on the secret (Key Vault RBAC: Key Vault Secrets User)
  3. App Service can reach Key Vault on the network (public, private endpoint, or VNet integration with allowed IP)

If any condition fails, the app setting resolves to the literal reference string β€” your code starts up, reads OPENAI_API_KEY=@Microsoft.KeyVault(...), and authentication to OpenAI fails. Always test with az webapp config appsettings list to confirm Microsoft.KeyVault.SecretReferenceState=Resolved.

Three patterns for getting secrets into a containerised App Service workload.
FeatureDirect app settingKey Vault referenceRead from Key Vault in code
Where the secret livesApp Service configKey VaultKey Vault
RotationManual: edit setting + restartEdit Key Vault β†’ restart appEdit Key Vault β†’ no restart needed if you re-fetch
Visible in portal configYes (resolved value)Yes (reference URI), value maskedNo (URI only if you store one)
Audit trailApp Service activity logKey Vault access policy logs + App Service logsKey Vault logs every read
Best forNon-secret configMost production secretsHighly sensitive secrets, frequent rotation, per-request retrieval

Pulling the image from ACR β€” use managed identity

Older docs show DOCKER_REGISTRY_SERVER_USERNAME / DOCKER_REGISTRY_SERVER_PASSWORD for ACR auth. Don’t use them. The modern pattern is:

# 1. Enable system-assigned managed identity on the web app
az webapp identity assign --name roo-inference --resource-group roo-prod

# 2. Grant the identity AcrPull on the registry
PRINCIPAL_ID=$(az webapp identity show -n roo-inference -g roo-prod --query principalId -o tsv)
az role assignment create \
  --assignee $PRINCIPAL_ID \
  --role AcrPull \
  --scope $(az acr show -n roo --query id -o tsv)

# 3. Configure App Service to use managed identity for the pull
az webapp config set \
  --name roo-inference \
  --resource-group roo-prod \
  --generic-configurations '{"acrUseManagedIdentityCreds": true}'

# 4. Set the image
az webapp config container set \
  --name roo-inference \
  --resource-group roo-prod \
  --container-image-name roo.azurecr.io/roo-vision:v3.4.1

No password ever leaves Azure. The web app pulls the image as itself.

Deployment slots β€” zero-downtime updates

Slots are independent App Service environments that share the same compute plan. The classic pattern:

# Create a staging slot
az webapp deployment slot create -n roo-inference -g roo-prod --slot staging

# Deploy a new image to staging
az webapp config container set -n roo-inference -g roo-prod \
  --slot staging --container-image-name roo.azurecr.io/roo-vision:v3.5.0

# Smoke test against the staging URL: https://roo-inference-staging.azurewebsites.net

# Swap β€” production now points to the new image, staging holds the old one
az webapp deployment slot swap -n roo-inference -g roo-prod \
  --slot staging --target-slot production

# If something's wrong β€” swap back. Old image is right there in staging.
az webapp deployment slot swap -n roo-inference -g roo-prod \
  --slot staging --target-slot production

Slot-specific app settings (Slot setting checkbox) stay with the slot during a swap β€” useful when staging and production hit different OpenAI endpoints or Key Vault references.

Real-world example: Priya's blue-green for the menu Q&A bot

BeanCraft Coffee deploys to App Service three times a week. Priya’s pipeline:

  1. Build image in ACR Tasks β†’ tag :v2.<run-id>
  2. Update staging slot to the new tag
  3. Run smoke tests (synthetic shoppers asking 20 standard questions)
  4. Swap staging β†’ production
  5. Watch error rate for 10 minutes; if it spikes, swap back

Total downtime per deploy: zero. Roll-back time: under 30 seconds. App Service slots make this trivial; doing the same on a single VM is a weekend project.

Sidecar containers (Linux only)

For Linux container apps, App Service supports running a small set of additional containers alongside your main image. Common uses:

SidecarWhy
OpenTelemetry collectorReceive traces from your main app on localhost, batch-export to Application Insights
Local model proxy (e.g., Phi-4 ONNX runtime)Run a small model in-process for low-latency inference, separate from the main API
Authentication proxyOAuth2 proxy in front of an internal API

Sidecars share the App Service’s network namespace β€” your main app reaches them on localhost. They share the App Service’s identity for outbound calls.

Key terms

Question

What does the WEBSITES_PORT app setting do?

Click or press Enter to reveal answer

Answer

It tells App Service which port your container listens on. App Service routes incoming HTTPS traffic to that port inside the container. If you build a Python app that listens on 8000, set WEBSITES_PORT=8000.

Click to flip back

Question

What is a Key Vault reference in App Service?

Click or press Enter to reveal answer

Answer

An app setting whose value is `@Microsoft.KeyVault(SecretUri=https://...vault.azure.net/secrets/MySecret)`. App Service resolves it to the actual secret value at startup using the app's managed identity. The container sees the real value; the portal shows only the URI.

Click to flip back

Question

How does App Service pull images from ACR without a password?

Click or press Enter to reveal answer

Answer

Enable a system- or user-assigned managed identity on the web app, grant it AcrPull on the registry, and set `acrUseManagedIdentityCreds: true`. The pull authenticates via Microsoft Entra. No DOCKER_REGISTRY_SERVER_PASSWORD needed.

Click to flip back

Question

What is a deployment slot?

Click or press Enter to reveal answer

Answer

A separate App Service environment that shares the App Service plan but has its own host name, settings, and image. Used for blue-green deploys: deploy to staging, smoke-test, then swap staging into production. Swap is near-instant; if production breaks, you can swap back to recover.

Click to flip back

Knowledge check

Knowledge Check

Mira's container reads its OpenAI API key from environment variable `OPENAI_API_KEY`. The security team wants the actual key stored only in Key Vault, with rotation visible in audit logs. Which approach satisfies both β€” the container still reads `OPENAI_API_KEY` AND the secret stays in Key Vault?

Knowledge Check

Theo deploys a new version of the clinical AI container to App Service. He wants to validate it against real-world traffic before exposing it to clinicians, and to roll back instantly if anything breaks. Which feature should he use?

Knowledge Check

Lin enabled a system-assigned managed identity on a web app and configured the image to pull from ACR. Pulls still fail. Which step did Lin most likely miss?