Skip to content

Runbook: Add a New Azure Environment

Estimated time: 4–8 hours (first environment), 2–3 hours (subsequent)
Audience: DevOps engineers
Prerequisites: Azure Owner access on the ERP subscription, Azure DevOps Project Administrator, Bicep CLI installed


Overview

This runbook provisions a new Azure environment for the Microtec ERP platform from scratch. Follow all steps in order — later steps depend on earlier ones.

services-config.json → Bicep params → Azure provision → Pipeline variables → Test

Step 1 — Define the Environment Name

Choose a short lowercase identifier for the new environment. Existing environments:

NameCIDRPurpose
dev10.0.0.0/16Development
stage10.1.0.0/16Staging / integration
preprod10.6.0.0/16Pre-production
uat10.5.0.0/16User acceptance testing
production10.2.0.0/16Production

Pick the next available CIDR block. For this example, the new environment is named qa with CIDR 10.3.0.0/16.


Step 2 — Update services-config.json

File: Devops/azure/config/container-backend/services-config.json

Each service entry has an environments object with per-environment overrides. Add a qa entry for every service:

jsonc
{
  "services": [
    {
      "name": "gateway",
      "image": "gateway-api",
      "environments": {
        "dev":        { "minReplicas": 1, "maxReplicas": 3 },
        "stage":      { "minReplicas": 1, "maxReplicas": 5 },
        "preprod":    { "minReplicas": 1, "maxReplicas": 5 },
        "uat":        { "minReplicas": 1, "maxReplicas": 3 },
        "production": { "minReplicas": 2, "maxReplicas": 10 },
        "qa":         { "minReplicas": 1, "maxReplicas": 3 }   // ← ADD THIS
      }
    }
    // Repeat for every service entry
  ]
}

Add the new environment to ALL service entries

The pipeline reads environments.{env} for every service. If any service is missing the new environment key, the pipeline will fail during deployment with a key-not-found error.


Step 3 — Create the Bicep Parameter File

File: Devops/azure/infrastructure/parameters/qa.bicepparam

Start by copying the closest existing environment's param file:

bash
cp Devops/azure/infrastructure/parameters/uat.bicepparam \
   Devops/azure/infrastructure/parameters/qa.bicepparam

Edit the new file:

bicep
// qa.bicepparam
using '../main.bicep'

param environment = 'qa'
param location    = 'uksouth'

// Networking
param vnetAddressPrefix = '10.3.0.0/16'
param acaSubnetPrefix   = '10.3.0.0/23'
param infraSubnetPrefix = '10.3.2.0/27'

// Resource naming (follows mic-erp-be-{env}-{resource} convention)
param resourcePrefix = 'mic-erp-be'

// SQL
param sqlServerResourceGroup = 'mic-backend-shared-sql-rg'
param sqlServerName          = 'mic-backend-shared-sql'

// Key Vault name (must be globally unique, max 24 chars)
param keyVaultName = 'mic-erp-be-qa-skv'

// Container Apps
param minReplicas = 1
param maxReplicas = 5

Resource naming the Bicep will create

The main.bicep template generates these resource groups based on the environment parameter:

Resource GroupContains
mic-erp-be-qa-network-rgVNet, subnets, NSG, NAT GW
mic-erp-be-qa-containers-rgPublic CAE, Private CAE, container apps
mic-erp-be-qa-storage-rgBlob storage (attachments)
mic-erp-be-fr-qa-storage-rgFrontend SWA storage
mic-erp-be-qa-monitoring-rgLog Analytics, App Insights
mic-erp-be-qa-shared-rgACR, Key Vault, managed identity
mic-backend-shared-sql-rgShared SQL (unchanged — do not create new)

Step 4 — Run the Bicep Deployment

bash
# Login and set subscription
az login
az account set --subscription "<ERP Subscription ID>"

# Validate first (dry run)
az deployment sub what-if \
  --location uksouth \
  --template-file Devops/azure/infrastructure/main.bicep \
  --parameters Devops/azure/infrastructure/parameters/qa.bicepparam

# Review what-if output carefully, then deploy
az deployment sub create \
  --location uksouth \
  --template-file Devops/azure/infrastructure/main.bicep \
  --parameters Devops/azure/infrastructure/parameters/qa.bicepparam \
  --name "mic-erp-qa-$(date +%Y%m%d)"

Expected deployment time: 15–25 minutes.

Monitor progress

Use the Azure Portal → Subscriptions → Deployments to see real-time provisioning status. Each module (network, containerApps, acr) appears as a nested deployment.


Step 5 — Verify Created Resources

After deployment completes, verify the key resources exist:

bash
ENV=qa
SUBSCRIPTION="<ERP Subscription ID>"

# Verify VNet
az network vnet show \
  --resource-group "mic-erp-be-${ENV}-network-rg" \
  --name "mic-erp-be-${ENV}-vnet" \
  --query "addressSpace.addressPrefixes" -o tsv

# Verify ACR
az acr show \
  --resource-group "mic-erp-be-${ENV}-shared-rg" \
  --name "micerpbe${ENV}acr" \
  --query "loginServer" -o tsv

# Verify Key Vault
az keyvault show \
  --resource-group "mic-erp-be-${ENV}-shared-rg" \
  --name "mic-erp-be-${ENV}-skv" \
  --query "properties.vaultUri" -o tsv

# Verify Public CAE
az containerapp env show \
  --resource-group "mic-erp-be-${ENV}-apps-public-rg" \
  --name "mic-erp-be-${ENV}-cae-public" \
  --query "properties.provisioningState" -o tsv

All outputs should be non-empty and provisioningState should be Succeeded.


Step 6 — Populate Key Vault Secrets

Secrets must be added to the new environment's Key Vault before any services can start. The minimum required secrets are:

bash
KV="mic-erp-be-qa-skv"

# SQL connection strings (one per service that uses SQL)
az keyvault secret set --vault-name $KV \
  --name "DefaultConnection" \
  --value "Server=mic-backend-shared-sql.database.windows.net;Database=mic_erp_qa;..."

# Redis
az keyvault secret set --vault-name $KV \
  --name "RedisConfiguration--Password" \
  --value "<redis-password>"

# RabbitMQ / Service Bus
az keyvault secret set --vault-name $KV \
  --name "ServiceBus--ConnectionString" \
  --value "<service-bus-connection-string>"

Key Vault naming convention

Use -- (double dash) in secret names, not __ (double underscore). Azure Key Vault does not allow double underscores. The hosting package translates -- back to : when loading configuration.


Step 7 — Update Pipeline Variables in Azure DevOps

In Azure DevOps, navigate to Pipelines → Library → Variable Groups and create a new variable group named microtec-erp-qa:

VariableValueSecret?
environmentqaNo
acr_namemicerpbeqaacrNo
resource_group_containersmic-erp-be-qa-containers-rgNo
keyvault_namemic-erp-be-qa-skvNo
azure_subscription_connectionmicrotec-erp-qa-serviceconnectionNo
nuget_pat<PAT>Yes

Then add qa to the environment allowlist in the pipeline template:

yaml
# Devops/azure/templates/devsecops/pipeline-template.yml
parameters:
  - name: environment
    type: string
    values: [dev, stage, preprod, uat, production, qa]   # ← add qa

Step 8 — Add Branch Mapping

The pipeline auto-detects the target environment from the triggering branch. Add the qa branch mapping:

yaml
# Devops/azure/templates/devsecops/stages/11-deploy-dev.yml
# (and the equivalent deploy-stage.yml)
variables:
  targetEnv: ${{ 
    eq(variables['Build.SourceBranch'], 'refs/heads/main') == 'true' ? 'dev' :
    eq(variables['Build.SourceBranch'], 'refs/heads/stage') == 'true' ? 'stage' :
    eq(variables['Build.SourceBranch'], 'refs/heads/qa') == 'true' ? 'qa' :     # ← add
    'dev' }}

Step 9 — Deploy All Services to the New Environment

Trigger the first full deployment by running the pipeline manually for each service with environment=qa, or merge to the qa branch if branch mapping is configured.

bash
# Trigger via Azure DevOps CLI (example for gateway service)
az pipelines run \
  --name "deploy-gateway" \
  --parameters "environment=qa" \
  --branch main

Step 10 — Verify Deployment

bash
ENV=qa
RG="mic-erp-be-${ENV}-containers-rg"

# Check all container apps are running
az containerapp list \
  --resource-group $RG \
  --query "[].{name:name, status:properties.runningStatus}" \
  -o table

# Hit the gateway health endpoint
GATEWAY_FQDN=$(az containerapp show \
  --name "mic-erp-be-${ENV}-gateway" \
  --resource-group $RG \
  --query "properties.configuration.ingress.fqdn" -o tsv)

curl -s "https://${GATEWAY_FQDN}/health" | jq .

Checklist

  • [ ] Environment name chosen; CIDR block selected (no overlap with existing environments)
  • [ ] services-config.json updated for ALL services
  • [ ] Bicep parameter file created (qa.bicepparam)
  • [ ] what-if reviewed and deployment executed
  • [ ] All resource groups verified in Azure Portal
  • [ ] Key Vault secrets populated
  • [ ] Azure DevOps variable group created (microtec-erp-qa)
  • [ ] Branch mapping updated in pipeline template
  • [ ] Pipeline environment gate added in Azure DevOps
  • [ ] All services deployed and health-checked
  • [ ] DNS configured for new environment (if public-facing)

Internal Documentation — Microtec Platform Team