- Reorganize docs into 'Core deployment guides' and 'Setup and configuration' subdirectories - Consolidate redundant documentation files (ACR, pipelines, deployment guides) - Add documentation consolidation plan - Update backend database factory and logger services - Update migration script and docker-compose configurations - Add PostgreSQL setup script
944 lines
27 KiB
Markdown
944 lines
27 KiB
Markdown
# 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 "<subscription-id-or-name>"
|
|
```
|
|
|
|
---
|
|
|
|
## 📦 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="<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):
|
|
|
|
```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 <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 <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-PIPELINES.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/<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
|
|
|
|
```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-ACR-SETUP.md` - ACR setup and usage
|
|
- `PRODUCTION-DEPLOYMENT.md` - General production deployment guide
|