Learning Path: Beginner ⭐ | Time: 25-35 minutes | Cost: $0-15/month
A complete, working Python Flask REST API deployed to Azure Container Apps using Azure Developer CLI (azd). This example demonstrates container deployment, auto-scaling, and monitoring basics.
- Deploy a containerized Python application to Azure
- Configure auto-scaling with scale-to-zero
- Implement health probes and readiness checks
- Monitor application logs and metrics
- Use Azure Developer CLI for rapid deployment
✅ Flask Application - Complete REST API with CRUD operations (src/app.py)
✅ Dockerfile - Production-ready container configuration
✅ Bicep Infrastructure - Container Apps environment and API deployment
✅ AZD Configuration - One-command deployment setup
✅ Health Probes - Liveness and readiness checks configured
✅ Auto-scaling - 0-10 replicas based on HTTP load
graph TD
subgraph ACA[Azure Container Apps Environment]
Flask[Flask API Container<br/>Health endpoints<br/>REST API<br/>Auto-scaling 0-10 replicas]
AppInsights[Application Insights]
end
- Azure Developer CLI (azd) - Install guide
- Azure subscription - Free account
- Docker Desktop - Install Docker (for local testing)
# Check azd version (need 1.5.0 or higher)
azd version
# Verify Azure login
azd auth login
# Check Docker (optional, for local testing)
docker --version| Phase | Duration | What Happens | |-------|----------|--------------|| | Environment setup | 30 seconds | Create azd environment | | Build container | 2-3 minutes | Docker build Flask app | | Provision infrastructure | 3-5 minutes | Create Container Apps, registry, monitoring | | Deploy application | 2-3 minutes | Push image and deploy to Container Apps | | Total | 8-12 minutes | Complete deployment ready |
# Navigate to the example
cd examples/container-app/simple-flask-api
# Initialize environment (choose unique name)
azd env new myflaskapi
# Deploy everything (infrastructure + application)
azd up
# You'll be prompted to:
# 1. Select Azure subscription
# 2. Choose location (e.g., eastus2)
# 3. Wait 8-12 minutes for deployment
# Get your API endpoint
azd env get-values
# Test the API
curl $(azd env get-value API_ENDPOINT)/healthExpected Output:
{
"status": "healthy",
"timestamp": "2025-11-19T10:30:00Z",
"service": "simple-flask-api",
"version": "1.0.0"
}# View deployed services
azd show
# Expected output shows:
# - Service: api
# - Endpoint: https://ca-api-[env].xxx.azurecontainerapps.io
# - Status: Running# Get API endpoint
API_URL=$(azd env get-value API_ENDPOINT)
# Test health
curl $API_URL/health
# Test root endpoint
curl $API_URL/
# Create an item
curl -X POST $API_URL/api/items \
-H "Content-Type: application/json" \
-d '{"name": "Test Item", "description": "My first item"}'
# Get all items
curl $API_URL/api/itemsSuccess Criteria:
- ✅ Health endpoint returns HTTP 200
- ✅ Root endpoint shows API information
- ✅ POST creates item and returns HTTP 201
- ✅ GET returns created items
# Stream live logs using azd monitor
azd monitor --logs
# Or use Azure CLI:
az containerapp logs show --name api --resource-group $RG_NAME --follow
# You should see:
# - Gunicorn startup messages
# - HTTP request logs
# - Application info logssimple-flask-api/
├── azure.yaml # AZD configuration
├── infra/
│ ├── main.bicep # Main infrastructure
│ ├── main.parameters.json
│ └── app/
│ ├── container-env.bicep
│ └── api.bicep
└── src/
├── app.py # Flask application
├── requirements.txt
└── Dockerfile
| Endpoint | Method | Description |
|---|---|---|
/health |
GET | Health check |
/api/items |
GET | List all items |
/api/items |
POST | Create new item |
/api/items/{id} |
GET | Get specific item |
/api/items/{id} |
PUT | Update item |
/api/items/{id} |
DELETE | Delete item |
# Set custom configuration
azd env set PORT 8000
azd env set LOG_LEVEL info
azd env set MAX_REPLICAS 20The API automatically scales based on HTTP traffic:
- Min Replicas: 0 (scales to zero when idle)
- Max Replicas: 10
- Concurrent Requests per Replica: 50
# Install dependencies
cd src
pip install -r requirements.txt
# Run the app
python app.py
# Test locally
curl http://localhost:8000/health# Build Docker image
docker build -t flask-api:local ./src
# Run container locally
docker run -p 8000:8000 flask-api:local
# Test container
curl http://localhost:8000/health# Deploy infrastructure and application
azd up# Deploy only application code (infrastructure unchanged)
azd deploy api# Update environment variables
azd env set API_KEY "new-api-key"
# Redeploy with new configuration
azd deploy api# Stream live logs using azd monitor
azd monitor --logs
# Or use Azure CLI for Container Apps:
az containerapp logs show --name api --resource-group $RG_NAME --follow
# View last 100 lines
az containerapp logs show --name api --resource-group $RG_NAME --tail 100# Open Azure Monitor dashboard
azd monitor --overview
# View specific metrics
az monitor metrics list \
--resource $(azd show --output json | jq -r '.services.api.resourceId') \
--metric "Requests,ResponseTime"curl $(azd show --output json | jq -r '.services.api.endpoint')/healthExpected response:
{
"status": "healthy",
"timestamp": "2025-11-19T10:30:00Z"
}curl -X POST $(azd show --output json | jq -r '.services.api.endpoint')/api/items \
-H "Content-Type: application/json" \
-d '{"name": "Test Item", "description": "A test item"}'curl $(azd show --output json | jq -r '.services.api.endpoint')/api/itemsThis deployment uses scale-to-zero, so you only pay when the API is processing requests:
- Idle cost: ~$0/month (scaled to zero)
- Active cost: ~$0.000024/second per replica
- Expected monthly cost (light usage): $5-15
# Scale down max replicas for dev
azd env set MAX_REPLICAS 3
# Use shorter idle timeout
azd env set SCALE_TO_ZERO_TIMEOUT 300 # 5 minutes# Check container logs using Azure CLI
az containerapp logs show --name api --resource-group $RG_NAME --tail 100
# Verify Docker image builds locally
docker build -t test ./src# Verify ingress is external
az containerapp show --name api --resource-group rg-simple-flask-api \
--query properties.configuration.ingress.external# Check CPU/Memory usage
az monitor metrics list \
--resource $(azd show --output json | jq -r '.services.api.resourceId') \
--metric "CPUPercentage,MemoryPercentage"
# Scale up resources if needed
az containerapp update --name api --resource-group rg-simple-flask-api \
--cpu 1.0 --memory 2Gi# Delete all resources
azd down --force --purge-
Add Database - Integrate Azure Cosmos DB or SQL Database
# Add Cosmos DB module to infra/main.bicep # Update app.py with database connection
-
Add Authentication - Implement Azure AD or API keys
# Add authentication middleware to app.py from functools import wraps
-
Set Up CI/CD - GitHub Actions workflow
# Create .github/workflows/deploy.yml name: Deploy to Azure on: [push]
-
Add Managed Identity - Secure access to Azure services
# Update infra/app/api.bicep identity: { type: 'SystemAssigned' }
- Database App - Complete example with SQL Database
- Microservices - Multi-service architecture
- Container Apps Master Guide - All container patterns
- 📚 AZD For Beginners Course - Main course home
- 📚 Container Apps Patterns - More deployment patterns
- 📚 AZD Templates Gallery - Community templates
- Flask Documentation - Flask framework guide
- Azure Container Apps - Official Azure docs
- Azure Developer CLI - azd command reference
- Container Apps Quickstart - Deploy your first app
- Python on Azure - Python development guide
- Bicep Language - Infrastructure as code
- Azure Portal - Manage resources visually
- VS Code Azure Extension - IDE integration
🎉 Congratulations! You've deployed a production-ready Flask API to Azure Container Apps with auto-scaling and monitoring.
Questions? Open an issue or check the FAQ