From 9d0898ae1f5f5fda6c483bc1605f781c741844be Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 12 Dec 2025 11:10:15 +0000 Subject: [PATCH 1/5] Initial plan From 4782a89c5534001a282797ed67e630648b0d0d38 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 12 Dec 2025 11:16:43 +0000 Subject: [PATCH 2/5] Add comprehensive Azure deployment documentation and automation Co-authored-by: abossard <86611+abossard@users.noreply.github.com> --- .github/workflows/azure-deploy.yml | 75 ++++++ README.md | 13 + azure-deploy.sh | 343 ++++++++++++++++++++++++ docs/AZURE_QUICK_REFERENCE.md | 179 +++++++++++++ docs/DEPLOY_AZURE.md | 402 +++++++++++++++++++++++++++++ 5 files changed, 1012 insertions(+) create mode 100644 .github/workflows/azure-deploy.yml create mode 100755 azure-deploy.sh create mode 100644 docs/AZURE_QUICK_REFERENCE.md create mode 100644 docs/DEPLOY_AZURE.md diff --git a/.github/workflows/azure-deploy.yml b/.github/workflows/azure-deploy.yml new file mode 100644 index 0000000..420e777 --- /dev/null +++ b/.github/workflows/azure-deploy.yml @@ -0,0 +1,75 @@ +name: Deploy to Azure Container Apps + +on: + push: + branches: [ main, master ] + workflow_dispatch: + inputs: + environment: + description: 'Deployment environment' + required: true + default: 'production' + type: choice + options: + - production + - staging + +env: + IMAGE_NAME: quart-react-demo + +jobs: + build-and-deploy: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Login to Azure + uses: azure/login@v1 + with: + creds: ${{ secrets.AZURE_CREDENTIALS }} + + - name: Set deployment variables + id: vars + run: | + echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT + echo "timestamp=$(date +%Y%m%d-%H%M%S)" >> $GITHUB_OUTPUT + + - name: Build and push to ACR + run: | + az acr build \ + --registry ${{ secrets.ACR_NAME }} \ + --image ${{ env.IMAGE_NAME }}:${{ steps.vars.outputs.sha_short }} \ + --image ${{ env.IMAGE_NAME }}:${{ steps.vars.outputs.timestamp }} \ + --image ${{ env.IMAGE_NAME }}:latest \ + --file Dockerfile \ + . + + - name: Deploy to Azure Container Apps + run: | + az containerapp update \ + --name ${{ secrets.CONTAINER_APP_NAME }} \ + --resource-group ${{ secrets.RESOURCE_GROUP }} \ + --image ${{ secrets.ACR_NAME }}.azurecr.io/${{ env.IMAGE_NAME }}:${{ steps.vars.outputs.sha_short }} + + - name: Get application URL + id: app-url + run: | + APP_URL=$(az containerapp show \ + --name ${{ secrets.CONTAINER_APP_NAME }} \ + --resource-group ${{ secrets.RESOURCE_GROUP }} \ + --query properties.configuration.ingress.fqdn \ + -o tsv) + echo "url=https://$APP_URL" >> $GITHUB_OUTPUT + + - name: Deployment summary + run: | + echo "### Deployment Complete! 🚀" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "- **Application URL**: ${{ steps.app-url.outputs.url }}" >> $GITHUB_STEP_SUMMARY + echo "- **Image Tag**: ${{ steps.vars.outputs.sha_short }}" >> $GITHUB_STEP_SUMMARY + echo "- **Commit**: ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY + echo "- **Resource Group**: ${{ secrets.RESOURCE_GROUP }}" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "View logs: \`az containerapp logs show --name ${{ secrets.CONTAINER_APP_NAME }} --resource-group ${{ secrets.RESOURCE_GROUP }} --follow\`" >> $GITHUB_STEP_SUMMARY diff --git a/README.md b/README.md index d8a5b2a..c5d1a40 100644 --- a/README.md +++ b/README.md @@ -14,10 +14,23 @@ - Frontend: React 18, Vite, FluentUI components, feature-first structure under `frontend/src/features` - Tests: Playwright E2E (`tests/e2e/app.spec.js`, `tests/e2e/ollama.spec.js`) +## 🚀 Deploy to Azure (5-10 minutes) + +Want to deploy this app to production? We've got you covered! + +**Quickest method**: `./azure-deploy.sh` - One command deploys everything to Azure Container Apps. + +📖 **[Complete Azure Deployment Guide](docs/DEPLOY_AZURE.md)** - Step-by-step instructions for: +- Azure Container Apps (recommended) +- Azure App Service +- CI/CD with GitHub Actions +- Environment configuration + ## Documentation All deep-dive guides now live under `docs/` for easier discovery: +- [🚀 **Azure Deployment**](docs/DEPLOY_AZURE.md) – **quickest way to deploy on Azure** (5-10 minutes) - [Ubuntu Installation Guide](docs/INSTALL_UBUNTU.md) – complete prerequisites installation for Ubuntu 22.04 LTS - [Quick Start](docs/QUICKSTART.md) – fastest path from clone to running servers - [Learning Guide](docs/LEARNING.md) – principles behind the architecture and code style diff --git a/azure-deploy.sh b/azure-deploy.sh new file mode 100755 index 0000000..592f832 --- /dev/null +++ b/azure-deploy.sh @@ -0,0 +1,343 @@ +#!/bin/bash + +# ============================================================================ +# Azure Container Apps Deployment Script +# ============================================================================ +# This script provides the QUICKEST way to deploy this Quart + React app to Azure +# It handles everything: resource creation, image building, and deployment +# +# Prerequisites: +# - Azure CLI installed (https://learn.microsoft.com/cli/azure/install-azure-cli) +# - Docker installed and running +# - Azure account with active subscription +# +# Usage: +# ./azure-deploy.sh +# +# The script will: +# 1. Check prerequisites +# 2. Login to Azure (if needed) +# 3. Create resource group +# 4. Create Azure Container Registry (ACR) +# 5. Build and push Docker image +# 6. Deploy to Azure Container Apps +# 7. Display your application URL +# ============================================================================ + +set -e # Exit on error + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Configuration (customize these if needed) +RESOURCE_GROUP="${RESOURCE_GROUP:-quart-react-demo-rg}" +LOCATION="${LOCATION:-eastus}" +ACR_NAME="${ACR_NAME:-quartreactdemo$(date +%s)}" +CONTAINER_APP_ENV="${CONTAINER_APP_ENV:-quart-react-env}" +CONTAINER_APP_NAME="${CONTAINER_APP_NAME:-quart-react-app}" +IMAGE_NAME="quart-react-demo" + +# ============================================================================ +# Helper Functions +# ============================================================================ + +print_header() { + echo -e "\n${BLUE}════════════════════════════════════════════════════════════════${NC}" + echo -e "${BLUE} $1${NC}" + echo -e "${BLUE}════════════════════════════════════════════════════════════════${NC}\n" +} + +print_success() { + echo -e "${GREEN}✓ $1${NC}" +} + +print_error() { + echo -e "${RED}✗ $1${NC}" +} + +print_warning() { + echo -e "${YELLOW}⚠ $1${NC}" +} + +print_info() { + echo -e "${BLUE}ℹ $1${NC}" +} + +# ============================================================================ +# Prerequisite Checks +# ============================================================================ + +check_prerequisites() { + print_header "Checking Prerequisites" + + # Check Azure CLI + if ! command -v az &> /dev/null; then + print_error "Azure CLI is not installed" + echo "Please install it from: https://learn.microsoft.com/cli/azure/install-azure-cli" + exit 1 + fi + print_success "Azure CLI is installed" + + # Check Docker + if ! command -v docker &> /dev/null; then + print_error "Docker is not installed" + echo "Please install it from: https://docs.docker.com/get-docker/" + exit 1 + fi + print_success "Docker is installed" + + # Check if Docker daemon is running + if ! docker info &> /dev/null; then + print_error "Docker daemon is not running" + echo "Please start Docker and try again" + exit 1 + fi + print_success "Docker daemon is running" + + # Check if Dockerfile exists + if [ ! -f "Dockerfile" ]; then + print_error "Dockerfile not found in current directory" + echo "Please run this script from the repository root" + exit 1 + fi + print_success "Dockerfile found" +} + +# ============================================================================ +# Azure Login +# ============================================================================ + +azure_login() { + print_header "Azure Login" + + # Check if already logged in + if az account show &> /dev/null; then + ACCOUNT_NAME=$(az account show --query name -o tsv) + print_success "Already logged in to Azure" + print_info "Current subscription: $ACCOUNT_NAME" + + read -p "Continue with this subscription? (y/n) " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + print_info "Initiating new login..." + az login + fi + else + print_info "Please login to Azure..." + az login + fi + + SUBSCRIPTION_ID=$(az account show --query id -o tsv) + print_success "Using subscription: $(az account show --query name -o tsv)" +} + +# ============================================================================ +# Create Resources +# ============================================================================ + +create_resource_group() { + print_header "Creating Resource Group" + + if az group exists --name $RESOURCE_GROUP | grep -q true; then + print_warning "Resource group '$RESOURCE_GROUP' already exists" + read -p "Use existing resource group? (y/n) " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + read -p "Enter a different resource group name: " RESOURCE_GROUP + create_resource_group + return + fi + else + print_info "Creating resource group '$RESOURCE_GROUP' in '$LOCATION'..." + az group create \ + --name $RESOURCE_GROUP \ + --location $LOCATION \ + --output none + print_success "Resource group created" + fi +} + +create_container_registry() { + print_header "Creating Azure Container Registry" + + # Check if ACR name is available + print_info "Checking ACR name availability..." + if ! az acr check-name --name $ACR_NAME --query nameAvailable -o tsv | grep -q true; then + print_warning "ACR name '$ACR_NAME' is not available" + ACR_NAME="quartreactdemo$(date +%s)" + print_info "Using new name: $ACR_NAME" + fi + + print_info "Creating container registry '$ACR_NAME'..." + az acr create \ + --resource-group $RESOURCE_GROUP \ + --name $ACR_NAME \ + --sku Basic \ + --admin-enabled true \ + --output none + + print_success "Container registry created" + + # Login to ACR + print_info "Logging in to ACR..." + az acr login --name $ACR_NAME + print_success "Logged in to ACR" +} + +# ============================================================================ +# Build and Push Image +# ============================================================================ + +build_and_push_image() { + print_header "Building and Pushing Docker Image" + + print_info "This may take 3-5 minutes..." + print_info "Building image in Azure Container Registry..." + + az acr build \ + --registry $ACR_NAME \ + --image $IMAGE_NAME:latest \ + --image $IMAGE_NAME:$(date +%Y%m%d-%H%M%S) \ + --file Dockerfile \ + . \ + --output table + + print_success "Image built and pushed successfully" +} + +# ============================================================================ +# Deploy to Container Apps +# ============================================================================ + +create_container_app_environment() { + print_header "Creating Container Apps Environment" + + # Check if environment already exists + if az containerapp env show --name $CONTAINER_APP_ENV --resource-group $RESOURCE_GROUP &> /dev/null; then + print_warning "Environment '$CONTAINER_APP_ENV' already exists" + else + print_info "Creating Container Apps environment..." + az containerapp env create \ + --name $CONTAINER_APP_ENV \ + --resource-group $RESOURCE_GROUP \ + --location $LOCATION \ + --output none + print_success "Environment created" + fi +} + +deploy_container_app() { + print_header "Deploying Container App" + + # Get ACR credentials + ACR_USERNAME=$(az acr credential show --name $ACR_NAME --query username -o tsv) + ACR_PASSWORD=$(az acr credential show --name $ACR_NAME --query passwords[0].value -o tsv) + ACR_SERVER="${ACR_NAME}.azurecr.io" + + # Check if app already exists + if az containerapp show --name $CONTAINER_APP_NAME --resource-group $RESOURCE_GROUP &> /dev/null; then + print_warning "Container app '$CONTAINER_APP_NAME' already exists" + print_info "Updating existing container app..." + + az containerapp update \ + --name $CONTAINER_APP_NAME \ + --resource-group $RESOURCE_GROUP \ + --image ${ACR_SERVER}/${IMAGE_NAME}:latest \ + --output none + + print_success "Container app updated" + else + print_info "Creating container app..." + + az containerapp create \ + --name $CONTAINER_APP_NAME \ + --resource-group $RESOURCE_GROUP \ + --environment $CONTAINER_APP_ENV \ + --image ${ACR_SERVER}/${IMAGE_NAME}:latest \ + --registry-server $ACR_SERVER \ + --registry-username $ACR_USERNAME \ + --registry-password $ACR_PASSWORD \ + --target-port 5001 \ + --ingress external \ + --cpu 0.5 \ + --memory 1.0Gi \ + --output none + + print_success "Container app created" + fi +} + +# ============================================================================ +# Display Results +# ============================================================================ + +display_results() { + print_header "Deployment Complete! 🎉" + + # Get app URL + APP_URL=$(az containerapp show \ + --name $CONTAINER_APP_NAME \ + --resource-group $RESOURCE_GROUP \ + --query properties.configuration.ingress.fqdn \ + -o tsv) + + echo -e "${GREEN}Your application is now live!${NC}\n" + echo -e "📱 Application URL: ${BLUE}https://$APP_URL${NC}" + echo -e "📦 Resource Group: ${BLUE}$RESOURCE_GROUP${NC}" + echo -e "🏗️ ACR Name: ${BLUE}$ACR_NAME${NC}" + echo -e "🚀 App Name: ${BLUE}$CONTAINER_APP_NAME${NC}" + echo + print_info "Opening your application in the browser..." + + # Try to open in browser (works on most systems) + if command -v xdg-open &> /dev/null; then + xdg-open "https://$APP_URL" &> /dev/null || true + elif command -v open &> /dev/null; then + open "https://$APP_URL" &> /dev/null || true + fi + + echo + print_header "Useful Commands" + echo "View logs:" + echo " az containerapp logs show --name $CONTAINER_APP_NAME --resource-group $RESOURCE_GROUP --follow" + echo + echo "Update app after code changes:" + echo " az acr build --registry $ACR_NAME --image $IMAGE_NAME:latest ." + echo " az containerapp update --name $CONTAINER_APP_NAME --resource-group $RESOURCE_GROUP --image ${ACR_NAME}.azurecr.io/${IMAGE_NAME}:latest" + echo + echo "Delete all resources:" + echo " az group delete --name $RESOURCE_GROUP --yes --no-wait" + echo + print_success "Done! Happy coding! 🚀" +} + +# ============================================================================ +# Main Execution +# ============================================================================ + +main() { + echo -e "${BLUE}" + echo "╔════════════════════════════════════════════════════════════════╗" + echo "║ ║" + echo "║ Azure Container Apps Deployment Script ║" + echo "║ Quart + React Demo Application ║" + echo "║ ║" + echo "╚════════════════════════════════════════════════════════════════╝" + echo -e "${NC}" + + check_prerequisites + azure_login + create_resource_group + create_container_registry + build_and_push_image + create_container_app_environment + deploy_container_app + display_results +} + +# Run main function +main diff --git a/docs/AZURE_QUICK_REFERENCE.md b/docs/AZURE_QUICK_REFERENCE.md new file mode 100644 index 0000000..0c32df9 --- /dev/null +++ b/docs/AZURE_QUICK_REFERENCE.md @@ -0,0 +1,179 @@ +# Azure Deployment Quick Reference + +## TL;DR - Deploy Now + +```bash +# One command deployment (5-10 minutes) +./azure-deploy.sh +``` + +That's it! The script handles everything automatically. + +--- + +## What You Need + +1. **Azure CLI** - [Install here](https://learn.microsoft.com/cli/azure/install-azure-cli) +2. **Docker** - [Install here](https://docs.docker.com/get-docker/) +3. **Azure account** - [Create free account](https://azure.microsoft.com/free/) + +--- + +## Manual Deployment (Copy-Paste Commands) + +```bash +# Set your preferences +RESOURCE_GROUP="quart-react-demo-rg" +LOCATION="eastus" +ACR_NAME="quartreactdemo$(date +%s)" +APP_NAME="quart-react-app" + +# Login to Azure +az login + +# Create resource group +az group create --name $RESOURCE_GROUP --location $LOCATION + +# Create and build in ACR (builds image in cloud) +az acr create --resource-group $RESOURCE_GROUP --name $ACR_NAME --sku Basic --admin-enabled true +az acr build --registry $ACR_NAME --image quart-react-demo:latest --file Dockerfile . + +# Create Container Apps environment +az containerapp env create --name quart-env --resource-group $RESOURCE_GROUP --location $LOCATION + +# Get ACR credentials +ACR_USERNAME=$(az acr credential show --name $ACR_NAME --query username -o tsv) +ACR_PASSWORD=$(az acr credential show --name $ACR_NAME --query passwords[0].value -o tsv) + +# Deploy to Container Apps +az containerapp create \ + --name $APP_NAME \ + --resource-group $RESOURCE_GROUP \ + --environment quart-env \ + --image ${ACR_NAME}.azurecr.io/quart-react-demo:latest \ + --registry-server ${ACR_NAME}.azurecr.io \ + --registry-username $ACR_USERNAME \ + --registry-password $ACR_PASSWORD \ + --target-port 5001 \ + --ingress external \ + --cpu 0.5 \ + --memory 1.0Gi + +# Get your app URL +az containerapp show --name $APP_NAME --resource-group $RESOURCE_GROUP --query properties.configuration.ingress.fqdn -o tsv +``` + +Your app will be live at: `https://..azurecontainerapps.io` + +--- + +## Useful Commands + +### View logs +```bash +az containerapp logs show --name $APP_NAME --resource-group $RESOURCE_GROUP --follow +``` + +### Update after code changes +```bash +az acr build --registry $ACR_NAME --image quart-react-demo:latest --file Dockerfile . +az containerapp update --name $APP_NAME --resource-group $RESOURCE_GROUP --image ${ACR_NAME}.azurecr.io/quart-react-demo:latest +``` + +### Add environment variables +```bash +az containerapp update \ + --name $APP_NAME \ + --resource-group $RESOURCE_GROUP \ + --set-env-vars \ + AZURE_OPENAI_ENDPOINT="your-endpoint" \ + AZURE_OPENAI_API_KEY="your-key" +``` + +### Delete everything +```bash +az group delete --name $RESOURCE_GROUP --yes --no-wait +``` + +--- + +## Cost Estimate + +**Free tier includes:** +- 180,000 vCPU-seconds per month +- 360,000 GiB-seconds per month + +**After free tier:** +- ~$5-20/month for small apps +- ~$5/month for Azure Container Registry + +--- + +## GitHub Actions Setup + +1. Create a service principal: +```bash +az ad sp create-for-rbac \ + --name "quart-react-sp" \ + --role contributor \ + --scopes /subscriptions//resourceGroups/ \ + --sdk-auth +``` + +2. Add these secrets to your GitHub repository: + - `AZURE_CREDENTIALS` - Output from command above + - `ACR_NAME` - Your container registry name + - `CONTAINER_APP_NAME` - Your app name + - `RESOURCE_GROUP` - Your resource group name + +3. Push to main/master branch - automatic deployment! 🚀 + +--- + +## Troubleshooting + +**Container won't start?** +- Check logs: `az containerapp logs show --name $APP_NAME --resource-group $RESOURCE_GROUP --follow` +- Verify port 5001 is exposed in Dockerfile + +**Image pull errors?** +- Verify ACR credentials: `az acr credential show --name $ACR_NAME` + +**502/503 errors?** +- Check if container is running: `az containerapp show --name $APP_NAME --resource-group $RESOURCE_GROUP` +- Verify ingress is on port 5001 + +--- + +## 📚 Full Documentation + +For detailed explanations, alternatives, and advanced configurations: +👉 **[Complete Azure Deployment Guide](DEPLOY_AZURE.md)** + +--- + +## Alternative: Docker Hub Deployment + +If you prefer Docker Hub over Azure Container Registry: + +```bash +# Build and push to Docker Hub +docker login +docker build -t yourusername/quart-react-demo:latest . +docker push yourusername/quart-react-demo:latest + +# Deploy using Docker Hub image +az containerapp create \ + --name $APP_NAME \ + --resource-group $RESOURCE_GROUP \ + --environment quart-env \ + --image yourusername/quart-react-demo:latest \ + --target-port 5001 \ + --ingress external \ + --cpu 0.5 \ + --memory 1.0Gi +``` + +--- + +**Ready to deploy?** Run: `./azure-deploy.sh` 🚀 diff --git a/docs/DEPLOY_AZURE.md b/docs/DEPLOY_AZURE.md new file mode 100644 index 0000000..608c6cf --- /dev/null +++ b/docs/DEPLOY_AZURE.md @@ -0,0 +1,402 @@ +# Deploy to Azure - Quick Start Guide + +This guide shows you the **quickest ways** to deploy this Quart + React application on Azure. + +## 🚀 Quickest Method: Azure Container Apps (Recommended) + +Azure Container Apps is the fastest and most modern way to deploy containerized applications. It handles scaling, load balancing, and HTTPS automatically. + +### Prerequisites +- Azure CLI installed ([Install here](https://learn.microsoft.com/cli/azure/install-azure-cli)) +- Docker installed +- An Azure account with an active subscription + +### One-Command Deployment + +We've created a script that automates the entire deployment: + +```bash +./azure-deploy.sh +``` + +This script will: +1. Login to Azure (if needed) +2. Create a resource group +3. Create an Azure Container Registry (ACR) +4. Build and push your Docker image +5. Deploy to Azure Container Apps +6. Display your application URL + +**Expected time: 5-10 minutes** + +### Manual Deployment (Step by Step) + +If you prefer to understand each step or customize the deployment: + +#### 1. Login to Azure + +```bash +az login +``` + +#### 2. Set variables + +```bash +# Customize these values +RESOURCE_GROUP="quart-react-demo-rg" +LOCATION="eastus" +ACR_NAME="quartreactdemo$(date +%s)" # Must be globally unique +CONTAINER_APP_ENV="quart-react-env" +CONTAINER_APP_NAME="quart-react-app" +``` + +#### 3. Create resource group + +```bash +az group create \ + --name $RESOURCE_GROUP \ + --location $LOCATION +``` + +#### 4. Create Azure Container Registry + +```bash +az acr create \ + --resource-group $RESOURCE_GROUP \ + --name $ACR_NAME \ + --sku Basic \ + --admin-enabled true +``` + +#### 5. Build and push Docker image + +```bash +# Login to ACR +az acr login --name $ACR_NAME + +# Build and push image +az acr build \ + --registry $ACR_NAME \ + --image quart-react-demo:latest \ + --file Dockerfile \ + . +``` + +#### 6. Create Container Apps environment + +```bash +az containerapp env create \ + --name $CONTAINER_APP_ENV \ + --resource-group $RESOURCE_GROUP \ + --location $LOCATION +``` + +#### 7. Deploy to Container Apps + +```bash +# Get ACR credentials +ACR_USERNAME=$(az acr credential show --name $ACR_NAME --query username -o tsv) +ACR_PASSWORD=$(az acr credential show --name $ACR_NAME --query passwords[0].value -o tsv) +ACR_SERVER="${ACR_NAME}.azurecr.io" + +# Deploy container app +az containerapp create \ + --name $CONTAINER_APP_NAME \ + --resource-group $RESOURCE_GROUP \ + --environment $CONTAINER_APP_ENV \ + --image ${ACR_SERVER}/quart-react-demo:latest \ + --registry-server $ACR_SERVER \ + --registry-username $ACR_USERNAME \ + --registry-password $ACR_PASSWORD \ + --target-port 5001 \ + --ingress external \ + --cpu 0.5 \ + --memory 1.0Gi +``` + +#### 8. Get your application URL + +```bash +az containerapp show \ + --name $CONTAINER_APP_NAME \ + --resource-group $RESOURCE_GROUP \ + --query properties.configuration.ingress.fqdn \ + -o tsv +``` + +Your app will be available at: `https://..azurecontainerapps.io` + +## 🔧 Alternative Method: Azure App Service (Web App for Containers) + +Azure App Service is another good option if you prefer traditional PaaS: + +### Quick deployment + +```bash +# Set variables +RESOURCE_GROUP="quart-react-demo-rg" +LOCATION="eastus" +APP_SERVICE_PLAN="quart-react-plan" +WEB_APP_NAME="quart-react-demo-$(date +%s)" +ACR_NAME="quartreactdemo$(date +%s)" + +# Create resource group +az group create --name $RESOURCE_GROUP --location $LOCATION + +# Create ACR and build image (same as above) +az acr create --resource-group $RESOURCE_GROUP --name $ACR_NAME --sku Basic --admin-enabled true +az acr login --name $ACR_NAME +az acr build --registry $ACR_NAME --image quart-react-demo:latest --file Dockerfile . + +# Create App Service Plan (Linux) +az appservice plan create \ + --name $APP_SERVICE_PLAN \ + --resource-group $RESOURCE_GROUP \ + --is-linux \ + --sku B1 + +# Create Web App +ACR_SERVER="${ACR_NAME}.azurecr.io" +az webapp create \ + --resource-group $RESOURCE_GROUP \ + --plan $APP_SERVICE_PLAN \ + --name $WEB_APP_NAME \ + --deployment-container-image-name ${ACR_SERVER}/quart-react-demo:latest + +# Configure ACR credentials +ACR_USERNAME=$(az acr credential show --name $ACR_NAME --query username -o tsv) +ACR_PASSWORD=$(az acr credential show --name $ACR_NAME --query passwords[0].value -o tsv) + +az webapp config container set \ + --name $WEB_APP_NAME \ + --resource-group $RESOURCE_GROUP \ + --docker-custom-image-name ${ACR_SERVER}/quart-react-demo:latest \ + --docker-registry-server-url https://${ACR_SERVER} \ + --docker-registry-server-user $ACR_USERNAME \ + --docker-registry-server-password $ACR_PASSWORD + +# Configure port +az webapp config appsettings set \ + --resource-group $RESOURCE_GROUP \ + --name $WEB_APP_NAME \ + --settings WEBSITES_PORT=5001 +``` + +Your app will be available at: `https://.azurewebsites.net` + +## 📦 Using Azure Portal (No CLI Required) + +If you prefer a GUI approach: + +### Method 1: Deploy to Container Apps via Portal + +1. **Login to Azure Portal**: https://portal.azure.com +2. **Create a Container App**: + - Search for "Container Apps" and click "Create" + - Select/create a resource group + - Enter app name and region + - Click "Next: Container" +3. **Configure Container**: + - Uncheck "Use quickstart image" + - For "Image source" select "Docker Hub or other registries" + - For "Image and tag" enter: `your-dockerhub-username/quart-react-demo:latest` + - (First push to Docker Hub: `docker build -t your-username/quart-react-demo . && docker push your-username/quart-react-demo`) + - Set "Target port" to `5001` +4. **Configure Ingress**: + - Enable "Ingress" + - Set "Ingress traffic" to "Accepting traffic from anywhere" + - Set "Target port" to `5001` +5. **Review + Create**: Click through and wait for deployment + +### Method 2: Deploy from Docker Hub + +1. **Push to Docker Hub first**: + ```bash + docker login + docker build -t yourusername/quart-react-demo:latest . + docker push yourusername/quart-react-demo:latest + ``` + +2. **Deploy in Azure Portal**: + - Go to Container Apps → Create + - Use the Docker Hub image: `yourusername/quart-react-demo:latest` + - Configure ingress on port 5001 + +## 🔐 Environment Variables (Optional) + +If you need to configure Azure OpenAI or other environment variables: + +### Container Apps + +```bash +az containerapp update \ + --name $CONTAINER_APP_NAME \ + --resource-group $RESOURCE_GROUP \ + --set-env-vars \ + AZURE_OPENAI_ENDPOINT="your-endpoint" \ + AZURE_OPENAI_API_KEY="your-key" \ + AZURE_OPENAI_DEPLOYMENT="your-deployment" \ + AZURE_OPENAI_API_VERSION="2024-05-01-preview" +``` + +### App Service + +```bash +az webapp config appsettings set \ + --resource-group $RESOURCE_GROUP \ + --name $WEB_APP_NAME \ + --settings \ + AZURE_OPENAI_ENDPOINT="your-endpoint" \ + AZURE_OPENAI_API_KEY="your-key" \ + AZURE_OPENAI_DEPLOYMENT="your-deployment" \ + AZURE_OPENAI_API_VERSION="2024-05-01-preview" +``` + +## 📊 Monitoring and Logs + +### View logs in Container Apps + +```bash +az containerapp logs show \ + --name $CONTAINER_APP_NAME \ + --resource-group $RESOURCE_GROUP \ + --follow +``` + +### View logs in App Service + +```bash +az webapp log tail \ + --name $WEB_APP_NAME \ + --resource-group $RESOURCE_GROUP +``` + +## 💰 Cost Estimates + +**Azure Container Apps** (Recommended): +- Free tier: First 180,000 vCPU-seconds, 360,000 GiB-seconds/month free +- Consumption plan: ~$0.000012 per vCPU-second, ~$0.000003 per GiB-second +- **Estimated cost for small app: $5-20/month** + +**Azure App Service** (B1 Basic): +- ~$13/month for Basic B1 tier +- Good for consistent, always-on workloads + +**Azure Container Registry**: +- Basic tier: $5/month +- Includes 10 GB storage + +## 🔄 Continuous Deployment + +### GitHub Actions (Recommended) + +Create `.github/workflows/azure-deploy.yml`: + +```yaml +name: Deploy to Azure Container Apps + +on: + push: + branches: [ main ] + +jobs: + build-and-deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Login to Azure + uses: azure/login@v1 + with: + creds: ${{ secrets.AZURE_CREDENTIALS }} + + - name: Build and push to ACR + run: | + az acr build \ + --registry ${{ secrets.ACR_NAME }} \ + --image quart-react-demo:${{ github.sha }} \ + --image quart-react-demo:latest \ + --file Dockerfile \ + . + + - name: Deploy to Container Apps + run: | + az containerapp update \ + --name ${{ secrets.CONTAINER_APP_NAME }} \ + --resource-group ${{ secrets.RESOURCE_GROUP }} \ + --image ${{ secrets.ACR_NAME }}.azurecr.io/quart-react-demo:${{ github.sha }} +``` + +**Setup**: Add these secrets to your GitHub repository: +- `AZURE_CREDENTIALS` - Service principal JSON +- `ACR_NAME` - Your ACR name +- `CONTAINER_APP_NAME` - Your app name +- `RESOURCE_GROUP` - Your resource group + +### Create service principal + +```bash +az ad sp create-for-rbac \ + --name "quart-react-demo-sp" \ + --role contributor \ + --scopes /subscriptions//resourceGroups/ \ + --sdk-auth +``` + +Copy the JSON output to GitHub Secrets as `AZURE_CREDENTIALS`. + +## 🐛 Troubleshooting + +### Container fails to start + +Check logs: +```bash +az containerapp logs show --name $CONTAINER_APP_NAME --resource-group $RESOURCE_GROUP --follow +``` + +Common issues: +- **Port mismatch**: Ensure Docker exposes 5001 and ingress targets 5001 +- **Health check failures**: Container Apps expects the app to respond on the target port +- **Memory limits**: Increase memory if app crashes: `--memory 2.0Gi` + +### Image pull errors + +```bash +# Verify ACR credentials +az acr credential show --name $ACR_NAME + +# Update container app with correct credentials +az containerapp update \ + --name $CONTAINER_APP_NAME \ + --resource-group $RESOURCE_GROUP \ + --registry-server ${ACR_NAME}.azurecr.io \ + --registry-username \ + --registry-password +``` + +### App responds with 502/503 + +- Check if the container is running: `az containerapp show ...` +- Verify the target port matches what Hypercorn binds to (5001) +- Check container logs for startup errors + +## 📚 Additional Resources + +- [Azure Container Apps Documentation](https://learn.microsoft.com/azure/container-apps/) +- [Azure App Service Documentation](https://learn.microsoft.com/azure/app-service/) +- [Deploying Python Web Apps on Azure](https://learn.microsoft.com/azure/developer/python/) +- [Quart Deployment Guide](https://quart.palletsprojects.com/en/latest/tutorials/deployment.html) + +## ✅ Quick Deployment Checklist + +- [ ] Install Azure CLI +- [ ] Login to Azure: `az login` +- [ ] Run deployment script: `./azure-deploy.sh` +- [ ] Wait 5-10 minutes +- [ ] Access your app at the provided URL +- [ ] (Optional) Configure environment variables +- [ ] (Optional) Set up GitHub Actions for CI/CD + +--- + +**Need help?** Open an issue or check the [Troubleshooting guide](TROUBLESHOOTING.md). From 5d59d88e1717c3dbd63b76b991ff9cf89203287c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 12 Dec 2025 11:18:37 +0000 Subject: [PATCH 3/5] Add Azure getting started guide and validation Co-authored-by: abossard <86611+abossard@users.noreply.github.com> --- docs/GETTING_STARTED_AZURE.md | 168 ++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 docs/GETTING_STARTED_AZURE.md diff --git a/docs/GETTING_STARTED_AZURE.md b/docs/GETTING_STARTED_AZURE.md new file mode 100644 index 0000000..9254e27 --- /dev/null +++ b/docs/GETTING_STARTED_AZURE.md @@ -0,0 +1,168 @@ +# Azure Deployment - Getting Started + +Welcome! This guide helps you deploy your Quart + React application to Azure in the quickest way possible. + +## 🎯 Choose Your Path + +### Path 1: Fully Automated (Recommended) ⚡ +**Time: 5-10 minutes** + +Just run one command and everything is done automatically: + +```bash +./azure-deploy.sh +``` + +The script will: +- ✓ Check your system has everything needed +- ✓ Login to Azure +- ✓ Create all required Azure resources +- ✓ Build and deploy your application +- ✓ Give you the live URL + +**Requirements:** +- Azure CLI ([install](https://learn.microsoft.com/cli/azure/install-azure-cli)) +- Docker ([install](https://docs.docker.com/get-docker/)) +- Azure account ([create free](https://azure.microsoft.com/free/)) + +### Path 2: Manual Step-by-Step 📖 +**Time: 10-15 minutes** + +Follow the detailed guide to understand every step: + +👉 **[Complete Azure Deployment Guide](DEPLOY_AZURE.md)** + +Includes: +- Azure Container Apps deployment (modern & recommended) +- Azure App Service deployment (traditional) +- Azure Portal deployment (GUI) +- Environment variables configuration +- Monitoring and troubleshooting + +### Path 3: Quick Copy-Paste 📋 +**Time: 8-12 minutes** + +Just copy and paste commands from: + +👉 **[Azure Quick Reference](AZURE_QUICK_REFERENCE.md)** + +Perfect if you know what you're doing. + +### Path 4: GitHub Actions (CI/CD) 🔄 +**Time: 15-20 minutes (one-time setup)** + +Automatic deployment on every git push: + +1. Deploy once using Path 1 or 2 +2. Configure GitHub secrets +3. Push code → automatic deployment! + +Details in: **[Complete Azure Deployment Guide - CI/CD Section](DEPLOY_AZURE.md#-continuous-deployment)** + +--- + +## 📊 Quick Comparison + +| Method | Time | Difficulty | Best For | +|--------|------|------------|----------| +| `./azure-deploy.sh` | 5-10 min | ⭐ Easy | Everyone | +| Manual CLI | 10-15 min | ⭐⭐ Medium | Learning | +| Azure Portal | 12-18 min | ⭐⭐ Medium | GUI lovers | +| GitHub Actions | 15-20 min | ⭐⭐⭐ Advanced | Production | + +--- + +## 💰 Cost + +**Free tier includes:** +- 180,000 vCPU-seconds/month +- 360,000 GiB-seconds/month + +**Most small apps run on free tier!** + +After free tier: ~$5-20/month for typical usage. + +Full details: [Pricing breakdown](DEPLOY_AZURE.md#-cost-estimates) + +--- + +## 🚀 Ready to Deploy? + +### For your first deployment: + +```bash +# Run the automated script +./azure-deploy.sh +``` + +### Already deployed? Update with: + +```bash +# Quick update command +az acr build --registry --image quart-react-demo:latest --file Dockerfile . +az containerapp update --name --resource-group --image .azurecr.io/quart-react-demo:latest +``` + +--- + +## 📚 Documentation Tree + +``` +docs/ +├── DEPLOY_AZURE.md ← Complete deployment guide (all methods) +├── AZURE_QUICK_REFERENCE.md ← Quick commands & troubleshooting +└── GETTING_STARTED_AZURE.md ← This file (you are here!) + +Root: +├── azure-deploy.sh ← One-command deployment script +└── .github/workflows/ + └── azure-deploy.yml ← CI/CD automation +``` + +--- + +## ❓ FAQ + +**Q: Do I need to know Azure to deploy?** +A: No! Just run `./azure-deploy.sh` and it handles everything. + +**Q: Will this cost money?** +A: Free tier covers small apps. You'll see costs before any charges. + +**Q: Can I deploy to my existing Azure subscription?** +A: Yes! The script uses your current Azure login. + +**Q: What if something goes wrong?** +A: Check [Troubleshooting Guide](DEPLOY_AZURE.md#-troubleshooting) + +**Q: How do I update my deployed app?** +A: Re-run `./azure-deploy.sh` or set up GitHub Actions for automatic updates. + +**Q: Can I customize the deployment?** +A: Yes! Edit variables at the top of `azure-deploy.sh` or follow the manual guide. + +--- + +## 🆘 Need Help? + +1. Check [Troubleshooting Guide](DEPLOY_AZURE.md#-troubleshooting) +2. Review [Azure Quick Reference](AZURE_QUICK_REFERENCE.md) +3. Open an issue on GitHub + +--- + +## ✅ Quick Checklist + +Before deploying, make sure you have: + +- [ ] Azure CLI installed (`az --version`) +- [ ] Docker installed and running (`docker --version`) +- [ ] Azure account (free tier is fine) +- [ ] You're in the repository root directory +- [ ] You've run `az login` at least once + +Then run: `./azure-deploy.sh` + +--- + +**Ready?** → `./azure-deploy.sh` 🚀 From cea51a08fc3e3b2fb7d5edaef8afb531c5a5aac3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 12 Dec 2025 11:20:54 +0000 Subject: [PATCH 4/5] Fix code review issues: improve ACR name uniqueness and correct doc link Co-authored-by: abossard <86611+abossard@users.noreply.github.com> --- azure-deploy.sh | 19 +++++++++++++------ docs/DEPLOY_AZURE.md | 2 +- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/azure-deploy.sh b/azure-deploy.sh index 592f832..a7f0360 100755 --- a/azure-deploy.sh +++ b/azure-deploy.sh @@ -164,13 +164,20 @@ create_resource_group() { create_container_registry() { print_header "Creating Azure Container Registry" - # Check if ACR name is available + # Check if ACR name is available and generate a unique one if needed print_info "Checking ACR name availability..." - if ! az acr check-name --name $ACR_NAME --query nameAvailable -o tsv | grep -q true; then - print_warning "ACR name '$ACR_NAME' is not available" - ACR_NAME="quartreactdemo$(date +%s)" - print_info "Using new name: $ACR_NAME" - fi + ATTEMPT=0 + while ! az acr check-name --name $ACR_NAME --query nameAvailable -o tsv | grep -q true; do + ATTEMPT=$((ATTEMPT + 1)) + if [ $ATTEMPT -gt 5 ]; then + print_error "Could not generate unique ACR name after 5 attempts" + exit 1 + fi + print_warning "ACR name '$ACR_NAME' is not available (attempt $ATTEMPT)" + ACR_NAME="quartreactdemo$(date +%s)${RANDOM:0:4}" + print_info "Trying new name: $ACR_NAME" + sleep 1 # Small delay to ensure timestamp changes + done print_info "Creating container registry '$ACR_NAME'..." az acr create \ diff --git a/docs/DEPLOY_AZURE.md b/docs/DEPLOY_AZURE.md index 608c6cf..3229310 100644 --- a/docs/DEPLOY_AZURE.md +++ b/docs/DEPLOY_AZURE.md @@ -399,4 +399,4 @@ az containerapp update \ --- -**Need help?** Open an issue or check the [Troubleshooting guide](TROUBLESHOOTING.md). +**Need help?** Open an issue or check the [Troubleshooting guide](docs/TROUBLESHOOTING.md). From 1a27e1d1b96413fcbcf6bb91993406bfb31a228c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 12 Dec 2025 11:24:05 +0000 Subject: [PATCH 5/5] Fix security: Add explicit permissions to GitHub Actions workflow Co-authored-by: abossard <86611+abossard@users.noreply.github.com> --- .github/workflows/azure-deploy.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/azure-deploy.yml b/.github/workflows/azure-deploy.yml index 420e777..8ebcf9e 100644 --- a/.github/workflows/azure-deploy.yml +++ b/.github/workflows/azure-deploy.yml @@ -17,6 +17,10 @@ on: env: IMAGE_NAME: quart-react-demo +permissions: + contents: read + id-token: write + jobs: build-and-deploy: runs-on: ubuntu-latest