CODE WITH SIBIN

Solving Real Problems with Real Code


Deploying a Python Web App (Django/Flask/FastAPI) to Azure App Service

This comprehensive guide will walk you through deploying your Python web application to Azure App Service.

Table of Contents

  1. Pre-Deployment Preparation
  2. Azure Setup
  3. Framework-Specific Deployment
  4. Database Configuration
  5. Advanced Configuration
  6. CI/CD Pipeline
  7. Monitoring and Scaling
  8. Security Best Practices
  9. Troubleshooting

Pre-Deployment Preparation

1. Application Readiness Checklist

Before deploying, ensure your application is production-ready:

  • Requirements filerequirements.txt or pyproject.toml with all dependencies
  • Environment variables: Use .env for development but prepare for Azure configuration
  • Static files: Configured for your framework (Django: collectstatic, Flask: typically static folder)
  • Database: Local DB for development, but prepared for cloud DB connection
  • Logging: Proper logging configuration
  • WSGI/ASGI: Entry point configured (application object for WSGI, appropriate ASGI setup)

2. Local Testing

  • Test with production settings locally
  • Run linters and tests
  • Check for hardcoded values that should be environment variables

Azure Setup

1. Prerequisites

  • Azure account (free tier available)
  • Azure CLI installed (az command)
  • Python 3.7+ (matching your target version)

2. Resource Group Creation

az group create --name myPythonAppResourceGroup --location eastus

3. App Service Plan

Choose based on your needs:

# Free tier (not recommended for production)
az appservice plan create --name myPythonAppPlan --resource-group myPythonAppResourceGroup --sku FREE --is-linux

# Production tier (B1 is the smallest production tier)
az appservice plan create --name myPythonAppPlan --resource-group myPythonAppResourceGroup --sku B1 --is-linux

4. Web App Creation

az webapp create --resource-group myPythonAppResourceGroup \
                 --plan myPythonAppPlan \
                 --name myPythonApp \
                 --runtime "PYTHON|3.9" \
                 --deployment-local-git

Note: Replace "3.9" with your Python version (3.7, 3.8, 3.9, 3.10 supported as of 2023)

Framework-Specific Deployment

Django Deployment

1. Configuration Adjustments

  • Update settings.py:
DEBUG = os.getenv('DEBUG', 'False') == 'True'
ALLOWED_HOSTS = [os.getenv('WEBSITE_HOSTNAME', 'localhost')]
SECRET_KEY = os.getenv('SECRET_KEY')  # Ensure this is set in Azure config

2. Static Files Configuration

  • Install WhiteNoise for static files:pip install whitenoise
  • Update settings.py:
MIDDLEWARE = [
    # ...
    'whitenoise.middleware.WhiteNoiseMiddleware',
    # ...
]

STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'

3. Deployment File Structure

Create .production/ folder with:

  • startup.sh (make it executable: chmod +x startup.sh)
#!/bin/bash

# Collect static files
echo "Collect static files"
python manage.py collectstatic --noinput

# Apply database migrations
echo "Apply database migrations"
python manage.py migrate

# Start server
echo "Starting server"
gunicorn --bind 0.0.0.0:8000 --workers 4 myproject.wsgi:application

4. Azure Configuration

az webapp config set --resource-group myPythonAppResourceGroup \
                    --name myPythonApp \
                    --startup-file ".production/startup.sh"

Flask Deployment

1. Application Factory Pattern (Recommended)

# app/__init__.py
from flask import Flask
from .config import Config

def create_app(config_class=Config):
    app = Flask(__name__)
    app.config.from_object(config_class)
    
    # Initialize extensions
    from .extensions import db, migrate
    db.init_app(app)
    migrate.init_app(app, db)
    
    # Register blueprints
    from .main import bp as main_bp
    app.register_blueprint(main_bp)
    
    return app

2. WSGI Entry Point

Create wsgi.py:

from app import create_app

application = create_app()

3. Deployment Configuration

  • .production/startup.sh:
#!/bin/bash

# Start server
gunicorn --bind 0.0.0.0:8000 --workers 4 wsgi:application

4. Azure Configuration

Same as Django configuration above.

FastAPI Deployment

1. ASGI Configuration

  • Install requirements:
pip install fastapi uvicorn[standard]

2. Deployment Options

Option 1: Gunicorn with Uvicorn workers

  • .production/startup.sh:
#!/bin/bash gunicorn -k uvicorn.workers.UvicornWorker -w 4 -b 0.0.0.0:8000 main:app

Option 2: Pure Uvicorn (for smaller apps)

  • .production/startup.sh:
#!/bin/bash

gunicorn -k uvicorn.workers.UvicornWorker -w 4 -b 0.0.0.0:8000 main:app

3. Azure Configuration

Same as previous frameworks.

Database Configuration

1. Azure Database for PostgreSQL (Recommended for Django)

az postgres server create --resource-group myPythonAppResourceGroup \
                         --name mypythonpostgres \
                         --location eastus \
                         --admin-user myadmin \
                         --admin-password ComplexPassword123! \
                         --sku-name B_Gen5_1 \
                         --version 11

2. Connection String Configuration

For Django:

az webapp config appsettings set --resource-group myPythonAppResourceGroup \
                                --name myPythonApp \
                                --settings DJANGO_DB_HOST="mypythonpostgres.postgres.database.azure.com" \
                                          DJANGO_DB_NAME="postgres" \
                                          DJANGO_DB_USER="myadmin@mypythonpostgres" \
                                          DJANGO_DB_PASSWORD="ComplexPassword123!"

For Flask/FastAPI with SQLAlchemy:

az webapp config appsettings set --resource-group myPythonAppResourceGroup \
                                --name myPythonApp \
                                --settings DATABASE_URL="postgresql://myadmin@mypythonpostgres:ComplexPassword123!@mypythonpostgres.postgres.database.azure.com/postgres?sslmode=require"

3. Database SSL Configuration

Most Azure databases require SSL. For Django:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': os.getenv('DJANGO_DB_NAME'),
        'USER': os.getenv('DJANGO_DB_USER'),
        'PASSWORD': os.getenv('DJANGO_DB_PASSWORD'),
        'HOST': os.getenv('DJANGO_DB_HOST'),
        'PORT': '5432',
        'OPTIONS': {
            'sslmode': 'require',
        },
    }
}

Advanced Configuration

1. Custom Domain Setup

  1. Purchase domain in Azure or bring your own
  2. Add DNS records
  3. Configure in App Service:
az webapp config hostname add --webapp-name myPythonApp \
                             --resource-group myPythonAppResourceGroup \
                             --hostname www.yourdomain.com

2. SSL/TLS Configuration

az webapp config ssl bind --resource-group myPythonAppResourceGroup \
                         --name myPythonApp \
                         --certificate-thumbprint [THUMBPRINT] \
                         --ssl-type SNI

3. Deployment Slots

# Create staging slot
az webapp deployment slot create --name myPythonApp \
                                --resource-group myPythonAppResourceGroup \
                                --slot staging

# Swap slots
az webapp deployment slot swap --name myPythonApp \
                              --resource-group myPythonAppResourceGroup \
                              --slot staging

4. Environment-Specific Settings

Use slot settings for different environments:

az webapp config appsettings set --resource-group myPythonAppResourceGroup \
                                --name myPythonApp \
                                --slot staging \
                                --settings ENVIRONMENT="staging"

CI/CD Pipeline

1. GitHub Actions

Create .github/workflows/azure-deploy.yml:

name: Deploy Python app to Azure

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    
    - name: Set up Python
      uses: actions/setup-python@v2
      with:
        python-version: '3.9'
    
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install -r requirements.txt
    
    - name: Run tests
      run: |
        python manage.py test
    
    - name: 'Deploy to Azure'
      uses: azure/webapps-deploy@v2
      with:
        app-name: 'myPythonApp'
        slot-name: 'production'
        publish-profile: ${{ secrets.AZURE_PUBLISH_PROFILE }}

2. Azure DevOps Pipeline

trigger:
- main

pool:
  vmImage: 'ubuntu-latest'

variables:
  python.version: '3.9'

steps:
- task: UsePythonVersion@0
  inputs:
    versionSpec: '$(python.version)'
  
- script: |
    python -m pip install --upgrade pip
    pip install -r requirements.txt
  displayName: 'Install dependencies'
  
- script: |
    python manage.py test
  displayName: 'Run tests'
  
- task: AzureWebApp@1
  inputs:
    azureSubscription: 'your-azure-subscription'
    appName: 'myPythonApp'
    slotName: 'production'
    package: $(System.DefaultWorkingDirectory)

Monitoring and Scaling

1. Application Insights

az monitor app-insights component create --app myPythonAppInsights \
                                        --location eastus \
                                        --resource-group myPythonAppResourceGroup \
                                        --application-type web

# Connect to your web app
az webapp config appsettings set --resource-group myPythonAppResourceGroup \
                                --name myPythonApp \
                                --settings APPLICATION_INSIGHTS_KEY="your-instrumentation-key" \
                                          APPINSIGHTS_INSTRUMENTATIONKEY="your-instrumentation-key"

2. Auto-scaling

# Create autoscale rule
az monitor autoscale create --resource-group myPythonAppResourceGroup \
                           --resource myPythonAppPlan \
                           --resource-type Microsoft.Web/serverfarms \
                           --name myPythonAppAutoscale \
                           --min-count 1 \
                           --max-count 5 \
                           --count 1

# Add scale condition
az monitor autoscale rule create --resource-group myPythonAppResourceGroup \
                                --autoscale-name myPythonAppAutoscale \
                                --condition "CpuPercentage > 70 avg 5m" \
                                --scale out 2

3. Log Streaming

az webapp log tail --resource-group myPythonAppResourceGroup --name myPythonApp

Security Best Practices

1. Environment Variables

Never commit secrets. Configure in Azure:

az webapp config appsettings set --resource-group myPythonAppResourceGroup \
                                --name myPythonApp \
                                --settings SECRET_KEY="your-secret-key-here"

2. Managed Identity for Database Access

# Enable managed identity
az webapp identity assign --resource-group myPythonAppResourceGroup \
                         --name myPythonApp

# Grant database access
az postgres server ad-admin create --resource-group myPythonAppResourceGroup \
                                  --server-name mypythonpostgres \
                                  --display-name myPythonApp \
                                  --object-id $(az webapp identity show --resource-group myPythonAppResourceGroup --name myPythonApp --query principalId -o tsv)

3. Network Security

  • Configure VNET integration
  • Set up IP restrictions
  • Enable private endpoints for databases

Troubleshooting

Common Issues and Solutions

  1. Application Not Starting
    • Check logs: az webapp log tail
    • Verify startup file is executable
    • Check Python version matches runtime
  2. Static Files Not Loading
    • Verify WhiteNoise configuration
    • Check STATIC_ROOT setting
    • Run collectstatic manually if needed
  3. Database Connection Issues
    • Verify connection string
    • Check firewall rules
    • Ensure SSL is properly configured
  4. Memory Errors
    • Reduce Gunicorn worker count
    • Upgrade App Service plan
    • Implement worker timeouts
  5. Deployment Failures
    • Check .deployment and deploy.cmd files
    • Verify all dependencies are in requirements.txt
    • Check for Python version conflicts

Diagnostic Tools

  • Kudu Console: Access via https://<app-name>.scm.azurewebsites.net
  • SSH Access: az webapp ssh --resource-group myPythonAppResourceGroup --name myPythonApp
  • Application Logs: az webapp log download --resource-group myPythonAppResourceGroup --name myPythonApp

Final Checklist Before Production

  1. All environment variables configured in Azure
  2. Database properly migrated and backed up
  3. Static files collected and configured
  4. Proper logging setup
  5. Monitoring configured (Application Insights)
  6. Backup strategy in place
  7. Security review completed
  8. Performance testing conducted
  9. Deployment rollback plan prepared
  10. DNS and SSL properly configured

By following this comprehensive guide, you should have a robust Python application running on Azure App Service with all the necessary production-grade configurations. Remember to monitor your application regularly and adjust scaling rules as your traffic patterns evolve.

Leave a Reply

Your email address will not be published. Required fields are marked *