Files
cmdb-insight/docs/Setup and configuration/AZURE-NEW-SUBSCRIPTION-SETUP.md
Bert Hausmans 57e4adc69c Remove JIRA_SCHEMA_ID from entire application
- Remove JIRA_SCHEMA_ID from all documentation, config files, and scripts
- Update generate-schema.ts to always auto-discover schemas dynamically
- Runtime application already discovers schemas via /objectschema/list API
- Build script now automatically selects schema with most objects
- Remove JIRA_SCHEMA_ID from docker-compose.yml, Azure setup scripts, and all docs
- Application is now fully schema-agnostic and discovers schemas automatically
2026-01-22 22:56:29 +01:00

26 KiB

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)

# macOS
brew install azure-cli

# Linux
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash

# Windows
# Download from: https://aka.ms/installazurecliwindows

Login to Azure

az login
az account list --output table
az account set --subscription "<subscription-id-or-name>"

📦 Step 1: Create Resource Group

Create a resource group to organize all resources:

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

If you already have an ACR for other applications, you can reuse it:

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

# 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

# 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).

# 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="<generate-secure-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):

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

# 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

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

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

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

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

# 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

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

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

# 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

# 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

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

# 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 <thumbprint> \
  --ssl-type SNI

Option 2: Import Existing Certificate

# Upload certificate
az webapp config ssl upload \
  --name $FRONTEND_APP_NAME \
  --resource-group $RESOURCE_GROUP \
  --certificate-file /path/to/certificate.pfx \
  --certificate-password <password>

Note: You'll need to update DNS records to point to your App Service. Get the IP address:

az webapp show --name $FRONTEND_APP_NAME --resource-group $RESOURCE_GROUP --query defaultHostName

Step 10: Verify Deployment

Check App Status

# 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

# Backend health check
curl https://${BACKEND_APP_NAME}.azurewebsites.net/api/health

# Frontend
curl https://${FRONTEND_APP_NAME}.azurewebsites.net

View Logs

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

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

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

    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 PipelinesEnvironments
    • 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:

    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-PIPELINES.md for complete setup guide.


🛠️ Troubleshooting

App Service Won't Start

# 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

# 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

# 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

# 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

# Create alert for app downtime
az monitor metrics alert create \
  --name "Backend-Down" \
  --resource-group $RESOURCE_GROUP \
  --scopes "/subscriptions/<subscription-id>/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

# 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


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-ACR-SETUP.md - ACR setup and usage
  • PRODUCTION-DEPLOYMENT.md - General production deployment guide