# Azure New Subscription Setup Guide Complete guide for setting up all required Azure resources for CMDB Insight in a new Azure subscription. ## 📋 Overview This guide will help you create and configure all necessary Azure resources to deploy the CMDB Insight application. The setup includes: ### Required Resources 1. **Resource Group** - Container for all resources 2. **Azure Container Registry (ACR)** - Store Docker images 3. **Azure Database for PostgreSQL** - Production database (recommended) 4. **Azure Key Vault** - Secure storage for secrets 5. **Azure App Service Plan** - Hosting plan for web apps 6. **Azure App Service (Backend)** - Backend API service 7. **Azure App Service (Frontend)** - Frontend web application 8. **Application Insights** - Monitoring and logging 9. **DNS & SSL** - Custom domain and HTTPS certificate ### Estimated Costs - **Basic Setup (SQLite)**: €17-35/month - **Recommended Setup (PostgreSQL)**: €36-62/month --- ## 🚀 Prerequisites Before starting, ensure you have: - [ ] Azure CLI installed (`az --version`) - [ ] Azure subscription with appropriate permissions - [ ] Docker installed (for local testing) - [ ] Access to Azure Portal - [ ] Jira credentials (OAuth client ID/secret or Personal Access Token) ### Install Azure CLI (if needed) ```bash # macOS brew install azure-cli # Linux curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash # Windows # Download from: https://aka.ms/installazurecliwindows ``` ### Login to Azure ```bash az login az account list --output table az account set --subscription "" ``` --- ## 📦 Step 1: Create Resource Group Create a resource group to organize all resources: ```bash # Set variables (customize as needed) RESOURCE_GROUP="rg-cmdb-insight-prod" LOCATION="westeurope" # or your preferred region # Create resource group az group create \ --name $RESOURCE_GROUP \ --location $LOCATION # Verify az group show --name $RESOURCE_GROUP ``` **Note**: Choose a location close to your users. Common options: - `westeurope` (Netherlands, Germany) - `northeurope` (Ireland, UK) - `eastus` (US East) --- ## 🐳 Step 2: Create or Use Existing Azure Container Registry (ACR) **Important**: Azure Container Registry can be **shared across multiple applications**. The repository name (`cmdb-insight`) is what separates this application from others in the same ACR. ### Option A: Use Existing ACR (Recommended if you have one) If you already have an ACR for other applications, you can reuse it: ```bash # Set variables - use your existing ACR name ACR_NAME="your-existing-acr" # Your existing ACR name ACR_RESOURCE_GROUP="rg-shared-services" # Resource group where ACR exists # Verify ACR exists az acr show --name $ACR_NAME --resource-group $ACR_RESOURCE_GROUP # Get ACR login server ACR_LOGIN_SERVER=$(az acr show --name $ACR_NAME --resource-group $ACR_RESOURCE_GROUP --query loginServer --output tsv) echo "ACR Login Server: $ACR_LOGIN_SERVER" ``` **Benefits of reusing ACR**: - ✅ Cost savings (one ACR for all apps) - ✅ Centralized image management - ✅ Easier to share images across teams - ✅ Better resource utilization ### Option B: Create New ACR If you don't have an ACR yet, create one: ```bash # Set variables ACR_NAME="yourcompanyacr" # Must be globally unique, lowercase, 5-50 chars, alphanumeric only ACR_RESOURCE_GROUP="rg-shared-services" # Or use your app resource group SKU="Standard" # Options: Basic, Standard, Premium # Create resource group for shared services (if needed) az group create --name $ACR_RESOURCE_GROUP --location westeurope # Create ACR az acr create \ --resource-group $ACR_RESOURCE_GROUP \ --name $ACR_NAME \ --sku $SKU \ --admin-enabled true # Get ACR login server ACR_LOGIN_SERVER=$(az acr show --name $ACR_NAME --resource-group $ACR_RESOURCE_GROUP --query loginServer --output tsv) echo "ACR Login Server: $ACR_LOGIN_SERVER" # Get admin credentials (save these securely) az acr credential show --name $ACR_NAME ``` **ACR SKU Comparison**: - **Basic**: €5/month - Development/test, 10GB storage - **Standard**: €20/month - Production, 100GB storage, geo-replication (recommended) - **Premium**: €50/month - Enterprise, 500GB storage, advanced security **Repository Structure in ACR**: ``` yourcompanyacr.azurecr.io/ ├── cmdb-insight/ ← This application │ ├── backend:latest │ └── frontend:latest ├── other-app/ ← Other applications │ ├── api:latest │ └── web:latest └── shared-services/ ← Shared images └── nginx:latest ``` ### Test ACR Connection ```bash # Login to ACR az acr login --name $ACR_NAME # Verify az acr repository list --name $ACR_NAME # List repositories (you'll see cmdb-insight after first push) az acr repository list --name $ACR_NAME --output table ``` --- ## 🗄️ Step 3: Create Azure Database for PostgreSQL PostgreSQL is recommended for production. Alternatively, you can use SQLite with Azure Storage (see Step 3B). ### Step 3A: PostgreSQL (Recommended) ```bash # Set variables DB_SERVER_NAME="cmdb-postgres-prod" # Must be globally unique RESOURCE_GROUP="rg-cmdb-insight-prod" DB_ADMIN_USER="cmdbadmin" DB_ADMIN_PASSWORD="" # Use a strong password! DB_NAME="cmdb" SKU="Standard_B1ms" # Burstable tier, 1 vCore, 2GB RAM # Generate secure password (save this!) DB_ADMIN_PASSWORD=$(openssl rand -base64 32) echo "Database Password: $DB_ADMIN_PASSWORD" # Create PostgreSQL Flexible Server az postgres flexible-server create \ --resource-group $RESOURCE_GROUP \ --name $DB_SERVER_NAME \ --location westeurope \ --admin-user $DB_ADMIN_USER \ --admin-password $DB_ADMIN_PASSWORD \ --sku-name $SKU \ --tier Burstable \ --storage-size 32 \ --version 15 \ --public-access 0.0.0.0 # Allow Azure services (restrict later if needed) # Create database az postgres flexible-server db create \ --resource-group $RESOURCE_GROUP \ --server-name $DB_SERVER_NAME \ --database-name $DB_NAME # Get connection string DB_CONNECTION_STRING="postgresql://${DB_ADMIN_USER}:${DB_ADMIN_PASSWORD}@${DB_SERVER_NAME}.postgres.database.azure.com:5432/${DB_NAME}?sslmode=require" echo "Database Connection String: $DB_CONNECTION_STRING" # Save connection details securely echo "DB_HOST=${DB_SERVER_NAME}.postgres.database.azure.com" > .env.azure echo "DB_USER=${DB_ADMIN_USER}" >> .env.azure echo "DB_PASSWORD=${DB_ADMIN_PASSWORD}" >> .env.azure echo "DB_NAME=${DB_NAME}" >> .env.azure ``` **PostgreSQL SKU Options**: - **Standard_B1ms**: €20-30/month - 1 vCore, 2GB RAM (recommended for 20 users) - **Standard_B2s**: €40-50/month - 2 vCores, 4GB RAM (for growth) - **Standard_D2s_v3**: €100+/month - 2 vCores, 8GB RAM (high performance) ### Step 3B: SQLite with Azure Storage (Alternative) If you prefer to use SQLite (simpler, but less scalable): ```bash # Set variables STORAGE_ACCOUNT_NAME="cmdbstorage$(openssl rand -hex 4)" # Must be globally unique, lowercase RESOURCE_GROUP="rg-cmdb-insight-prod" # Create storage account az storage account create \ --resource-group $RESOURCE_GROUP \ --name $STORAGE_ACCOUNT_NAME \ --location westeurope \ --sku Standard_LRS # Get storage account key STORAGE_KEY=$(az storage account keys list \ --resource-group $RESOURCE_GROUP \ --account-name $STORAGE_ACCOUNT_NAME \ --query "[0].value" --output tsv) echo "Storage Account: $STORAGE_ACCOUNT_NAME" echo "Storage Key: $STORAGE_KEY" ``` **Note**: SQLite works but has limitations with concurrent users. PostgreSQL is recommended for production. --- ## 🔐 Step 4: Create Azure Key Vault Key Vault securely stores secrets like API keys, passwords, and tokens. ```bash # Set variables KEY_VAULT_NAME="kv-cmdb-insight-prod" # Must be globally unique RESOURCE_GROUP="rg-cmdb-insight-prod" # Create Key Vault az keyvault create \ --name $KEY_VAULT_NAME \ --resource-group $RESOURCE_GROUP \ --location westeurope \ --sku standard # Verify az keyvault show --name $KEY_VAULT_NAME --resource-group $RESOURCE_GROUP ``` ### Add Secrets to Key Vault ```bash # Set your actual values JIRA_PAT="your-jira-personal-access-token" SESSION_SECRET=$(openssl rand -hex 32) JIRA_OAUTH_CLIENT_ID="your-oauth-client-id" JIRA_OAUTH_CLIENT_SECRET="your-oauth-client-secret" JIRA_SCHEMA_ID="your-schema-id" # Add secrets az keyvault secret set \ --vault-name $KEY_VAULT_NAME \ --name "JiraPat" \ --value "$JIRA_PAT" az keyvault secret set \ --vault-name $KEY_VAULT_NAME \ --name "SessionSecret" \ --value "$SESSION_SECRET" az keyvault secret set \ --vault-name $KEY_VAULT_NAME \ --name "JiraOAuthClientId" \ --value "$JIRA_OAUTH_CLIENT_ID" az keyvault secret set \ --vault-name $KEY_VAULT_NAME \ --name "JiraOAuthClientSecret" \ --value "$JIRA_OAUTH_CLIENT_SECRET" az keyvault secret set \ --vault-name $KEY_VAULT_NAME \ --name "JiraSchemaId" \ --value "$JIRA_SCHEMA_ID" # If using PostgreSQL, add database password az keyvault secret set \ --vault-name $KEY_VAULT_NAME \ --name "DatabasePassword" \ --value "$DB_ADMIN_PASSWORD" ``` --- ## 📊 Step 5: Create Application Insights Application Insights provides monitoring, logging, and performance metrics. ```bash # Set variables APP_INSIGHTS_NAME="appi-cmdb-insight-prod" RESOURCE_GROUP="rg-cmdb-insight-prod" # Create Application Insights az monitor app-insights component create \ --app $APP_INSIGHTS_NAME \ --location westeurope \ --resource-group $RESOURCE_GROUP \ --application-type web # Get Instrumentation Key INSTRUMENTATION_KEY=$(az monitor app-insights component show \ --app $APP_INSIGHTS_NAME \ --resource-group $RESOURCE_GROUP \ --query instrumentationKey --output tsv) echo "Instrumentation Key: $INSTRUMENTATION_KEY" ``` **Note**: Application Insights Basic tier is free up to 5GB/month, which is sufficient for most small applications. --- ## 🖥️ Step 6: Create App Service Plan App Service Plan defines the compute resources for your web apps. ```bash # Set variables APP_SERVICE_PLAN_NAME="plan-cmdb-insight-prod" RESOURCE_GROUP="rg-cmdb-insight-prod" SKU="B1" # Basic tier, 1 vCore, 1.75GB RAM # Create App Service Plan (Linux) az appservice plan create \ --name $APP_SERVICE_PLAN_NAME \ --resource-group $RESOURCE_GROUP \ --sku $SKU \ --is-linux # Verify az appservice plan show --name $APP_SERVICE_PLAN_NAME --resource-group $RESOURCE_GROUP ``` **App Service Plan SKU Options**: - **B1**: €15-25/month - 1 vCore, 1.75GB RAM (recommended for 20 users) - **B2**: €30-40/month - 2 vCores, 3.5GB RAM - **S1**: €50-70/month - 1 vCore, 1.75GB RAM (Standard tier, better performance) --- ## 🚀 Step 7: Create App Services (Backend & Frontend) Create two web apps: one for backend API and one for frontend. ### Step 7A: Create Backend App Service ```bash # Set variables BACKEND_APP_NAME="cmdb-backend-prod" # Must be globally unique RESOURCE_GROUP="rg-cmdb-insight-prod" APP_SERVICE_PLAN_NAME="plan-cmdb-insight-prod" ACR_NAME="cmdbinsightacr" # From Step 2 # Create backend web app az webapp create \ --name $BACKEND_APP_NAME \ --resource-group $RESOURCE_GROUP \ --plan $APP_SERVICE_PLAN_NAME \ --deployment-container-image-name "${ACR_NAME}.azurecr.io/cmdb-insight/backend:latest" # Enable Managed Identity (for ACR access) az webapp identity assign \ --name $BACKEND_APP_NAME \ --resource-group $RESOURCE_GROUP # Get Managed Identity Principal ID BACKEND_PRINCIPAL_ID=$(az webapp identity show \ --name $BACKEND_APP_NAME \ --resource-group $RESOURCE_GROUP \ --query principalId --output tsv) # Grant ACR pull permissions ACR_ID=$(az acr show --name $ACR_NAME --resource-group $RESOURCE_GROUP --query id --output tsv) az role assignment create \ --assignee $BACKEND_PRINCIPAL_ID \ --role AcrPull \ --scope $ACR_ID # Configure container settings az webapp config container set \ --name $BACKEND_APP_NAME \ --resource-group $RESOURCE_GROUP \ --docker-custom-image-name "${ACR_NAME}.azurecr.io/cmdb-insight/backend:latest" \ --docker-registry-server-url "https://${ACR_NAME}.azurecr.io" # Set environment variables az webapp config appsettings set \ --name $BACKEND_APP_NAME \ --resource-group $RESOURCE_GROUP \ --settings \ NODE_ENV=production \ PORT=3001 \ DATABASE_TYPE=postgres \ DATABASE_URL="@Microsoft.KeyVault(SecretUri=https://${KEY_VAULT_NAME}.vault.azure.net/secrets/DatabasePassword/)" \ JIRA_HOST=https://jira.zuyderland.nl \ JIRA_AUTH_METHOD=oauth \ JIRA_OAUTH_CLIENT_ID="@Microsoft.KeyVault(SecretUri=https://${KEY_VAULT_NAME}.vault.azure.net/secrets/JiraOAuthClientId/)" \ JIRA_OAUTH_CLIENT_SECRET="@Microsoft.KeyVault(SecretUri=https://${KEY_VAULT_NAME}.vault.azure.net/secrets/JiraOAuthClientSecret/)" \ JIRA_OAUTH_CALLBACK_URL="https://${BACKEND_APP_NAME}.azurewebsites.net/api/auth/callback" \ JIRA_SCHEMA_ID="@Microsoft.KeyVault(SecretUri=https://${KEY_VAULT_NAME}.vault.azure.net/secrets/JiraSchemaId/)" \ SESSION_SECRET="@Microsoft.KeyVault(SecretUri=https://${KEY_VAULT_NAME}.vault.azure.net/secrets/SessionSecret/)" \ FRONTEND_URL="https://${FRONTEND_APP_NAME}.azurewebsites.net" \ APPINSIGHTS_INSTRUMENTATIONKEY="${INSTRUMENTATION_KEY}" # Grant Key Vault access to backend az keyvault set-policy \ --name $KEY_VAULT_NAME \ --object-id $BACKEND_PRINCIPAL_ID \ --secret-permissions get list # Enable HTTPS only az webapp update \ --name $BACKEND_APP_NAME \ --resource-group $RESOURCE_GROUP \ --https-only true ``` ### Step 7B: Create Frontend App Service ```bash # Set variables FRONTEND_APP_NAME="cmdb-frontend-prod" # Must be globally unique RESOURCE_GROUP="rg-cmdb-insight-prod" APP_SERVICE_PLAN_NAME="plan-cmdb-insight-prod" ACR_NAME="cmdbinsightacr" # From Step 2 # Create frontend web app az webapp create \ --name $FRONTEND_APP_NAME \ --resource-group $RESOURCE_GROUP \ --plan $APP_SERVICE_PLAN_NAME \ --deployment-container-image-name "${ACR_NAME}.azurecr.io/cmdb-insight/frontend:latest" # Enable Managed Identity az webapp identity assign \ --name $FRONTEND_APP_NAME \ --resource-group $RESOURCE_GROUP # Get Managed Identity Principal ID FRONTEND_PRINCIPAL_ID=$(az webapp identity show \ --name $FRONTEND_APP_NAME \ --resource-group $RESOURCE_GROUP \ --query principalId --output tsv) # Grant ACR pull permissions az role assignment create \ --assignee $FRONTEND_PRINCIPAL_ID \ --role AcrPull \ --scope $ACR_ID # Configure container settings az webapp config container set \ --name $FRONTEND_APP_NAME \ --resource-group $RESOURCE_GROUP \ --docker-custom-image-name "${ACR_NAME}.azurecr.io/cmdb-insight/frontend:latest" \ --docker-registry-server-url "https://${ACR_NAME}.azurecr.io" # Set environment variables az webapp config appsettings set \ --name $FRONTEND_APP_NAME \ --resource-group $RESOURCE_GROUP \ --settings \ VITE_API_URL="https://${BACKEND_APP_NAME}.azurewebsites.net/api" # Enable HTTPS only az webapp update \ --name $FRONTEND_APP_NAME \ --resource-group $RESOURCE_GROUP \ --https-only true ``` --- ## 🔄 Step 8: Build and Push Docker Images Before the apps can run, you need to build and push Docker images to ACR. ### Option A: Using Script (Recommended) ```bash # Navigate to project root cd /path/to/cmdb-insight # Set environment variables export ACR_NAME="cmdbinsightacr" # Your ACR name export REPO_NAME="cmdb-insight" # Build and push ./scripts/build-and-push-azure.sh ``` ### Option B: Manual Build and Push ```bash # Set variables ACR_NAME="cmdbinsightacr" REGISTRY="${ACR_NAME}.azurecr.io" REPO_NAME="cmdb-insight" # Login to ACR az acr login --name $ACR_NAME # Build backend docker build -t ${REGISTRY}/${REPO_NAME}/backend:latest \ -f backend/Dockerfile.prod ./backend # Build frontend docker build -t ${REGISTRY}/${REPO_NAME}/frontend:latest \ -f frontend/Dockerfile.prod ./frontend # Push images docker push ${REGISTRY}/${REPO_NAME}/backend:latest docker push ${REGISTRY}/${REPO_NAME}/frontend:latest # Verify az acr repository list --name $ACR_NAME az acr repository show-tags --name $ACR_NAME --repository ${REPO_NAME}/backend az acr repository show-tags --name $ACR_NAME --repository ${REPO_NAME}/frontend ``` --- ## 🌐 Step 9: Configure Custom Domain and SSL (Optional) If you have a custom domain (e.g., `cmdb.yourcompany.com`): ### Step 9A: Add Custom Domain ```bash # Set variables FRONTEND_APP_NAME="cmdb-frontend-prod" BACKEND_APP_NAME="cmdb-backend-prod" CUSTOM_DOMAIN="cmdb.yourcompany.com" RESOURCE_GROUP="rg-cmdb-insight-prod" # Add custom domain to frontend az webapp config hostname add \ --webapp-name $FRONTEND_APP_NAME \ --resource-group $RESOURCE_GROUP \ --hostname $CUSTOM_DOMAIN # Add custom domain to backend (if needed) az webapp config hostname add \ --webapp-name $BACKEND_APP_NAME \ --resource-group $RESOURCE_GROUP \ --hostname "api.${CUSTOM_DOMAIN}" ``` ### Step 9B: Configure SSL Certificate **Option 1: App Service Managed Certificate (Free, Recommended)** ```bash # Create managed certificate for frontend az webapp config ssl create \ --name $FRONTEND_APP_NAME \ --resource-group $RESOURCE_GROUP \ --hostname $CUSTOM_DOMAIN # Bind certificate az webapp config ssl bind \ --name $FRONTEND_APP_NAME \ --resource-group $RESOURCE_GROUP \ --certificate-thumbprint \ --ssl-type SNI ``` **Option 2: Import Existing Certificate** ```bash # Upload certificate az webapp config ssl upload \ --name $FRONTEND_APP_NAME \ --resource-group $RESOURCE_GROUP \ --certificate-file /path/to/certificate.pfx \ --certificate-password ``` **Note**: You'll need to update DNS records to point to your App Service. Get the IP address: ```bash az webapp show --name $FRONTEND_APP_NAME --resource-group $RESOURCE_GROUP --query defaultHostName ``` --- ## ✅ Step 10: Verify Deployment ### Check App Status ```bash # Check backend az webapp show --name $BACKEND_APP_NAME --resource-group $RESOURCE_GROUP --query state # Check frontend az webapp show --name $FRONTEND_APP_NAME --resource-group $RESOURCE_GROUP --query state # Start apps if needed az webapp start --name $BACKEND_APP_NAME --resource-group $RESOURCE_GROUP az webapp start --name $FRONTEND_APP_NAME --resource-group $RESOURCE_GROUP ``` ### Test Health Endpoints ```bash # Backend health check curl https://${BACKEND_APP_NAME}.azurewebsites.net/api/health # Frontend curl https://${FRONTEND_APP_NAME}.azurewebsites.net ``` ### View Logs ```bash # Backend logs az webapp log tail --name $BACKEND_APP_NAME --resource-group $RESOURCE_GROUP # Frontend logs az webapp log tail --name $FRONTEND_APP_NAME --resource-group $RESOURCE_GROUP ``` --- ## 🔧 Step 11: Configure Database Schema If using PostgreSQL, you need to initialize the database schema: ```bash # Connect to database and run schema initialization # Option 1: Using psql psql "postgresql://${DB_ADMIN_USER}:${DB_ADMIN_PASSWORD}@${DB_SERVER_NAME}.postgres.database.azure.com:5432/${DB_NAME}?sslmode=require" # Option 2: Using Azure Cloud Shell or local script # The application will create tables automatically on first run # Or use the migration scripts in backend/scripts/ ``` **Note**: The application will automatically create the required database schema on first startup if it doesn't exist. --- ## 📝 Step 12: Update Environment Variables (If Needed) If you need to update any configuration: ```bash # Update backend settings az webapp config appsettings set \ --name $BACKEND_APP_NAME \ --resource-group $RESOURCE_GROUP \ --settings \ NEW_SETTING=value # Update frontend settings az webapp config appsettings set \ --name $FRONTEND_APP_NAME \ --resource-group $RESOURCE_GROUP \ --settings \ VITE_API_URL="https://${BACKEND_APP_NAME}.azurewebsites.net/api" # Restart apps to apply changes az webapp restart --name $BACKEND_APP_NAME --resource-group $RESOURCE_GROUP az webapp restart --name $FRONTEND_APP_NAME --resource-group $RESOURCE_GROUP ``` --- ## 🔄 Step 13: Set Up CI/CD with Automated Deployment ### Azure DevOps Pipeline Setup The project includes an automated pipeline that builds, pushes, and deploys your application. 1. **Create Service Connections**: **A) Docker Registry Connection (for building images)**: - Go to Azure DevOps → Project Settings → Service connections - Create new **Docker Registry** connection - Select **Azure Container Registry** - Choose your subscription and ACR - Name: `zuyderland-cmdb-acr-connection` (or match your variable) **B) Azure Resource Manager Connection (for deployment)**: - Create new **Azure Resource Manager** connection - Select your subscription - Name: `zuyderland-cmdb-subscription` (or match your variable) 2. **Configure Pipeline Variables**: Update `azure-pipelines.yml` with your values: ```yaml variables: acrName: 'cmdbinsightacr' # Your ACR name resourceGroup: 'rg-cmdb-insight-prod' # Your resource group backendAppName: 'cmdb-backend-prod' # Your backend app name frontendAppName: 'cmdb-frontend-prod' # Your frontend app name azureSubscription: 'zuyderland-cmdb-subscription' # Azure service connection dockerRegistryServiceConnection: 'zuyderland-cmdb-acr-connection' ``` 3. **Create Environment**: - Go to **Pipelines** → **Environments** - Create environment: `production` - (Optional) Add approvals for manual deployment control 4. **Run Pipeline**: - Push to `main` branch → **Automatically builds AND deploys** - Pipeline will: - Build Docker images - Push to ACR - Deploy to App Services - Verify deployment ### Zero-Downtime Deployment (Optional) For production with zero downtime, use deployment slots: 1. **Create Staging Slots**: ```bash az webapp deployment slot create \ --name $BACKEND_APP_NAME \ --resource-group $RESOURCE_GROUP \ --slot staging az webapp deployment slot create \ --name $FRONTEND_APP_NAME \ --resource-group $RESOURCE_GROUP \ --slot staging ``` 2. **Use Advanced Pipeline**: - Use `azure-pipelines-slots.yml` instead - Deploys to staging first - Swaps to production after verification **See `docs/AZURE-PIPELINE-DEPLOYMENT.md` for complete setup guide.** --- ## 🛠️ Troubleshooting ### App Service Won't Start ```bash # Check logs az webapp log tail --name $BACKEND_APP_NAME --resource-group $RESOURCE_GROUP # Check container logs az webapp log show --name $BACKEND_APP_NAME --resource-group $RESOURCE_GROUP # Check app status az webapp show --name $BACKEND_APP_NAME --resource-group $RESOURCE_GROUP --query state ``` ### ACR Authentication Issues ```bash # Re-authenticate az acr login --name $ACR_NAME # Check Managed Identity permissions az role assignment list --assignee $BACKEND_PRINCIPAL_ID --scope $ACR_ID ``` ### Database Connection Issues ```bash # Test database connection psql "postgresql://${DB_ADMIN_USER}:${DB_ADMIN_PASSWORD}@${DB_SERVER_NAME}.postgres.database.azure.com:5432/${DB_NAME}?sslmode=require" # Check firewall rules az postgres flexible-server firewall-rule list \ --resource-group $RESOURCE_GROUP \ --name $DB_SERVER_NAME ``` ### Key Vault Access Issues ```bash # Check Key Vault policies az keyvault show --name $KEY_VAULT_NAME --resource-group $RESOURCE_GROUP # Verify Managed Identity has access az keyvault show-policy --name $KEY_VAULT_NAME ``` --- ## 📊 Monitoring ### Application Insights 1. Go to Azure Portal → Application Insights → Your app 2. View: - **Live Metrics**: Real-time performance - **Application Map**: Service dependencies - **Logs**: Query application logs - **Metrics**: Performance metrics ### Set Up Alerts ```bash # Create alert for app downtime az monitor metrics alert create \ --name "Backend-Down" \ --resource-group $RESOURCE_GROUP \ --scopes "/subscriptions//resourceGroups/${RESOURCE_GROUP}/providers/Microsoft.Web/sites/${BACKEND_APP_NAME}" \ --condition "avg AvailabilityPercentage < 99" \ --window-size 5m \ --evaluation-frequency 1m ``` --- ## 💰 Cost Optimization ### Current Setup Costs | Resource | SKU | Estimated Monthly Cost | |----------|-----|------------------------| | App Service Plan | B1 | €15-25 | | PostgreSQL | Standard_B1ms | €20-30 | | Container Registry | Basic | €5 | | Key Vault | Standard | €1-2 | | Application Insights | Basic | €0-5 (free tier) | | **Total** | | **€41-67/month** | ### Cost Saving Tips 1. **Use Basic tier ACR** for development (€5 vs €20) 2. **Application Insights Basic** is free up to 5GB/month 3. **Stop App Services** when not in use (dev/test environments) 4. **Use SQLite** instead of PostgreSQL (saves €20-30/month, but less scalable) --- ## 📚 Next Steps 1. **Configure DNS**: Point your domain to App Service 2. **Set up SSL**: Configure HTTPS certificate 3. **Test Application**: Verify all features work 4. **Set up Monitoring**: Configure alerts 5. **Document Access**: Share URLs and credentials with team 6. **Backup Strategy**: Plan for database backups (if needed) --- ## 🔗 Useful Commands Reference ```bash # List all resources az resource list --resource-group $RESOURCE_GROUP --output table # Get resource IDs az acr show --name $ACR_NAME --resource-group $RESOURCE_GROUP --query id az postgres flexible-server show --name $DB_SERVER_NAME --resource-group $RESOURCE_GROUP --query id # Export resource configuration az group export --name $RESOURCE_GROUP --output-file resources.json # Delete all resources (careful!) az group delete --name $RESOURCE_GROUP --yes --no-wait ``` --- ## 📖 Additional Resources - [Azure App Service Documentation](https://docs.microsoft.com/azure/app-service/) - [Azure Container Registry Documentation](https://docs.microsoft.com/azure/container-registry/) - [Azure Database for PostgreSQL Documentation](https://docs.microsoft.com/azure/postgresql/) - [Azure Key Vault Documentation](https://docs.microsoft.com/azure/key-vault/) - [Application Insights Documentation](https://docs.microsoft.com/azure/azure-monitor/app/app-insights-overview) --- ## ✅ Deployment Checklist - [ ] Resource Group created - [ ] Azure Container Registry created and accessible - [ ] PostgreSQL database created (or SQLite storage configured) - [ ] Key Vault created with all secrets - [ ] Application Insights created - [ ] App Service Plan created - [ ] Backend App Service created and configured - [ ] Frontend App Service created and configured - [ ] Docker images built and pushed to ACR - [ ] Apps started and running - [ ] Health checks passing - [ ] Custom domain configured (if applicable) - [ ] SSL certificate configured (if applicable) - [ ] Monitoring and alerts configured - [ ] Team access configured - [ ] Documentation updated --- **🎉 Congratulations! Your CMDB Insight application is now deployed to Azure!** For questions or issues, refer to: - `AZURE-APP-SERVICE-DEPLOYMENT.md` - Detailed App Service deployment guide - `AZURE-CONTAINER-REGISTRY.md` - ACR setup and usage - `PRODUCTION-DEPLOYMENT.md` - General production deployment guide