06 - Hands-on Deployment Guide
A comprehensive hands-on guide to deploying a Python backend API to Azure Container Apps, including real-world debugging of policies, architectures, and caching.
Deploy a Containerized API to Azure Container Apps
In this lab, we deploy a containerized backend API to Azure Container Apps. Rather than using automated scripts, we walk through the manual Azure CLI steps to thoroughly understand the infrastructure.
We will also explore and solve real-world cloud engineering hurdles such as Azure policies, CPU architecture mismatches (Apple Silicon vs Cloud), image caching, and Express Environment limitations.
1. Environment Setup
First, install the necessary Azure CLI extensions and register the Resource Providers so your subscription is allowed to create these resources:
az extension add --name containerapp
az extension add --name log-analytics
az provider register --namespace Microsoft.App
az provider register --namespace Microsoft.OperationalInsights
az provider register --namespace Microsoft.ContainerRegistryNext, set up environment variables to make the commands reusable.
Important Concept - Variable Evaluation: In bash/zsh, variables are evaluated at the moment they are exported. If you change
UNIQUE_IDlater, you must re-exportACR_NAMEandACR_SERVERso they pick up the new value!
export UNIQUE_ID="20098" # Change to random numbers to ensure global uniqueness
export RESOURCE_GROUP="rg-aca-lab"
export LOCATION="eastasia"
export ACR_NAME="acr$UNIQUE_ID"
export ACA_ENVIRONMENT="aca-env-$UNIQUE_ID"
export CONTAINER_APP_NAME="ai-api"
export CONTAINER_IMAGE="ai-api:v2"
export TARGET_PORT="8000"
export MODEL_NAME="gpt-5.4-mini"
export EMBEDDINGS_API_KEY="demo-key-12345"
export ACR_SERVER="$ACR_NAME.azurecr.io"2. Resource Group and Container Registry
Create the resource group to hold our resources.
az group create --name $RESOURCE_GROUP --location $LOCATIONNext, create an Azure Container Registry (ACR). This acts as a private secure vault for your Docker images.
az acr create --resource-group $RESOURCE_GROUP --name $ACR_NAME --sku Basic --admin-enabled falseReal-World Error: RequestDisallowedByAzure
If you are using an Azure for Students or free tier subscription, you might encounter this error when trying to deploy to US regions (like eastus or westus):
Resource 'acr123' was disallowed by Azure: This policy maintains a set of best available regions...Why: Microsoft applies policies to student accounts restricting high-demand regions to prevent capacity issues.
The Fix: Use student-friendly regions like eastasia, centralindia, swedencentral, or japaneast. (Update your $LOCATION variable and recreate the Resource Group).
3. Building and Pushing the Docker Image
Normally, you would use ACR Tasks (az acr build) to build the image in the cloud. However, ACR Tasks are disabled for free/student accounts to prevent crypto-mining abuse (yielding a TasksOperationsNotAllowed error).
The Fix: Build the image locally using Docker Desktop and push it to Azure.
First, seamlessly link your local Docker to Azure:
az acr login --name $ACR_NAMEReal-World Error: Unsupported image platform: architecture=arm64
If you are on an Apple Silicon Mac (M1/M2/M3), running a standard docker build will create an arm64 image. However, Azure Container Apps defaults to standard Intel/AMD processors (amd64). If you deploy an arm64 image, the container will crash.
The Fix: Use Docker's BuildKit to cross-compile the image for Linux/AMD64 using the --platform flag.
# Ensure you are in the directory containing the `api/` folder and Dockerfile
docker build --platform linux/amd64 -t $ACR_NAME.azurecr.io/$CONTAINER_IMAGE api/
# Push to Azure
docker push $ACR_NAME.azurecr.io/$CONTAINER_IMAGEReal-World Error: Azure Image Tag Caching
If you deploy a broken image (like the arm64 one), Azure Container Apps will cache the manifest. If you rebuild the correct amd64 image and push it using the exact same tag (e.g., :v1), Azure will often reuse the broken cached version!
The Fix: Always bump your tags (e.g., update $CONTAINER_IMAGE to ai-api:v2) when pushing fixes.
4. Deploying to Container Apps
Create the Container Apps Environment. This provides a fully managed Kubernetes-like cluster boundary with a shared virtual network and Log Analytics workspace.
az containerapp env create --name $ACA_ENVIRONMENT --resource-group $RESOURCE_GROUP --location $LOCATIONReal-World Error: ExpressEnvironmentFeatureNotSupported
Azure uses "Express Environments" in certain regions/tiers to save costs. These environments do not support System-Assigned Managed Identities for ACR authentication.
The Fix: We must fallback to using the ACR's Admin Username and Password.
- Enable the admin account on the registry:
az acr update -n $ACR_NAME --admin-enabled true- Store the password in a variable:
export ACR_PASSWORD=$(az acr credential show -n $ACR_NAME --query "passwords[0].value" -o tsv)Now, deploy the Container App passing the credentials directly:
az containerapp create \
--name $CONTAINER_APP_NAME \
--resource-group $RESOURCE_GROUP \
--environment $ACA_ENVIRONMENT \
--image "$ACR_SERVER/$CONTAINER_IMAGE" \
--ingress external \
--target-port $TARGET_PORT \
--registry-server "$ACR_SERVER" \
--registry-username $ACR_NAME \
--registry-password $ACR_PASSWORD(Notice --ingress external automatically sets up HTTPS and a public load balancer).
5. Configuring Secrets Securely
We must securely store API keys rather than exposing them as plain text environment variables. We store the key in the Container App's secret store, then bind an environment variable (EMBEDDINGS_API_KEY) to it.
- Store the secret:
az containerapp secret set -n $CONTAINER_APP_NAME -g $RESOURCE_GROUP \
--secrets embeddings-api-key=$EMBEDDINGS_API_KEY- Update the app configuration: (Note: Updating configuration automatically restarts the app and creates a new Revision).
az containerapp update -n $CONTAINER_APP_NAME -g $RESOURCE_GROUP \
--set-env-vars MODEL_NAME=$MODEL_NAME EMBEDDINGS_API_KEY=secretref:embeddings-api-key6. Verify and Cleanup
Grab your live, public FQDN (Fully Qualified Domain Name) and test the endpoints:
export FQDN=$(az containerapp show -n $CONTAINER_APP_NAME -g $RESOURCE_GROUP --query properties.configuration.ingress.fqdn -o tsv)
echo "Your app is live at: https://$FQDN"
# Verify health
curl -s "https://$FQDN/health"
# Verify the secret is properly loaded
curl -s "https://$FQDN/"Once verified, clean up the resources so you don't incur Pay-As-You-Go charges. Deleting the Resource Group deletes everything inside it.
az group delete --name $RESOURCE_GROUP --no-wait --yes05 - Verify Deployments
Master Day 2 operations by learning how to debug Azure Container Apps using the hierarchy of Apps, Revisions, Replicas, and dual-layer Logging.
06 - Manage containers in Azure Container Apps
Manage container apps across the day-two lifecycle. Update images, manage revisions, diagnose failing deployments, tune resources and scaling, and troubleshoot with logs and health probes.
