Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 

README.md

Simple Flask API - Container App Example

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.

🎯 What You'll Learn

  • 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

📦 What's Included

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

Architecture

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
Loading

Prerequisites

Required

Verify Prerequisites

# 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

⏱️ Deployment Timeline

| 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 |

Quick Start

# 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)/health

Expected Output:

{
  "status": "healthy",
  "timestamp": "2025-11-19T10:30:00Z",
  "service": "simple-flask-api",
  "version": "1.0.0"
}

✅ Verify Deployment

Step 1: Check Deployment Status

# View deployed services
azd show

# Expected output shows:
# - Service: api
# - Endpoint: https://ca-api-[env].xxx.azurecontainerapps.io
# - Status: Running

Step 2: Test API Endpoints

# 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/items

Success Criteria:

  • ✅ Health endpoint returns HTTP 200
  • ✅ Root endpoint shows API information
  • ✅ POST creates item and returns HTTP 201
  • ✅ GET returns created items

Step 3: View Logs

# 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 logs

Project Structure

simple-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

API Endpoints

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

Configuration

Environment Variables

# Set custom configuration
azd env set PORT 8000
azd env set LOG_LEVEL info
azd env set MAX_REPLICAS 20

Scaling Configuration

The API automatically scales based on HTTP traffic:

  • Min Replicas: 0 (scales to zero when idle)
  • Max Replicas: 10
  • Concurrent Requests per Replica: 50

Development

Run Locally

# Install dependencies
cd src
pip install -r requirements.txt

# Run the app
python app.py

# Test locally
curl http://localhost:8000/health

Build and Test Container

# 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

Deployment

Full Deployment

# Deploy infrastructure and application
azd up

Code-Only Deployment

# Deploy only application code (infrastructure unchanged)
azd deploy api

Update Configuration

# Update environment variables
azd env set API_KEY "new-api-key"

# Redeploy with new configuration
azd deploy api

Monitoring

View Logs

# 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

Monitor Metrics

# 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"

Testing

Health Check

curl $(azd show --output json | jq -r '.services.api.endpoint')/health

Expected response:

{
  "status": "healthy",
  "timestamp": "2025-11-19T10:30:00Z"
}

Create Item

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"}'

Get All Items

curl $(azd show --output json | jq -r '.services.api.endpoint')/api/items

Cost Optimization

This 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

Reduce Costs Further

# 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

Troubleshooting

Container Won't Start

# 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

API Not Accessible

# Verify ingress is external
az containerapp show --name api --resource-group rg-simple-flask-api \
  --query properties.configuration.ingress.external

High Response Times

# 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

Clean Up

# Delete all resources
azd down --force --purge

Next Steps

Expand This Example

  1. Add Database - Integrate Azure Cosmos DB or SQL Database

    # Add Cosmos DB module to infra/main.bicep
    # Update app.py with database connection
  2. Add Authentication - Implement Azure AD or API keys

    # Add authentication middleware to app.py
    from functools import wraps
  3. Set Up CI/CD - GitHub Actions workflow

    # Create .github/workflows/deploy.yml
    name: Deploy to Azure
    on: [push]
  4. Add Managed Identity - Secure access to Azure services

    # Update infra/app/api.bicep
    identity: { type: 'SystemAssigned' }

Related Examples

Learning Resources

Additional Resources

Documentation

Tutorials

Tools


🎉 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