Add Azure deployment automation and documentation

- Add separate deployment pipeline (azure-pipelines-deploy.yml) for App Service deployment
- Add advanced pipeline with deployment slots (azure-pipelines-slots.yml)
- Restore azure-pipelines.yml to build-only (no deployment)
- Add comprehensive Azure setup documentation:
  - AZURE-NEW-SUBSCRIPTION-SETUP.md: Complete step-by-step Azure resource setup
  - AZURE-RESOURCES-OVERVIEW.md: Quick reference for all Azure resources
  - AZURE-ACR-SHARED-SETUP.md: Guide for shared Container Registry
  - AZURE-ACR-NAMING-RECOMMENDATION.md: Naming recommendations for Zuyderland
  - AZURE-PIPELINE-DEPLOYMENT.md: Automated deployment setup guide
  - AZURE-PIPELINE-QUICK-REFERENCE.md: Quick reference for pipeline variables
  - AZURE-PIPELINES-USAGE.md: Guide for using build and deployment pipelines
- Add setup script (scripts/setup-azure-resources.sh) for automated resource creation
- Support for shared ACR across multiple applications
This commit is contained in:
2026-01-21 23:03:48 +01:00
parent 52f851c1f3
commit 42a04e6cb3
10 changed files with 3176 additions and 0 deletions

247
azure-pipelines-slots.yml Normal file
View File

@@ -0,0 +1,247 @@
# Azure DevOps Pipeline - Build, Push and Deploy with Deployment Slots
# Advanced version with zero-downtime deployment using staging slots
trigger:
branches:
include:
- main
tags:
include:
- 'v*'
pool:
vmImage: 'ubuntu-latest'
variables:
# Azure Container Registry configuratie
acrName: 'zdlas' # Pas aan naar jouw ACR naam
repositoryName: 'cmdb-insight'
dockerRegistryServiceConnection: 'zuyderland-cmdb-acr-connection'
# Azure App Service configuratie
resourceGroup: 'rg-cmdb-insight-prod'
backendAppName: 'cmdb-backend-prod'
frontendAppName: 'cmdb-frontend-prod'
azureSubscription: 'zuyderland-cmdb-subscription'
# Deployment configuratie
imageTag: '$(Build.BuildId)'
deployToProduction: true
useDeploymentSlots: true # Enable deployment slots
stagingSlotName: 'staging'
stages:
- stage: Build
displayName: 'Build and Push Docker Images'
jobs:
- job: BuildImages
displayName: 'Build Docker Images'
steps:
- task: Docker@2
displayName: 'Build and Push Backend Image'
inputs:
command: buildAndPush
repository: '$(repositoryName)/backend'
dockerfile: 'backend/Dockerfile.prod'
containerRegistry: '$(dockerRegistryServiceConnection)'
tags: |
$(imageTag)
latest
- task: Docker@2
displayName: 'Build and Push Frontend Image'
inputs:
command: buildAndPush
repository: '$(repositoryName)/frontend'
dockerfile: 'frontend/Dockerfile.prod'
containerRegistry: '$(dockerRegistryServiceConnection)'
tags: |
$(imageTag)
latest
- task: PowerShell@2
displayName: 'Output Image URLs'
inputs:
targetType: 'inline'
script: |
$backendImage = "$(acrName).azurecr.io/$(repositoryName)/backend:$(imageTag)"
$frontendImage = "$(acrName).azurecr.io/$(repositoryName)/frontend:$(imageTag)"
Write-Host "##vso[task.setvariable variable=backendImage;isOutput=true]$backendImage"
Write-Host "##vso[task.setvariable variable=frontendImage;isOutput=true]$frontendImage"
Write-Host "Backend Image: $backendImage"
Write-Host "Frontend Image: $frontendImage"
- stage: DeployToStaging
displayName: 'Deploy to Staging Slot'
dependsOn: Build
condition: and(succeeded(), eq(variables['deployToProduction'], true), eq(variables['useDeploymentSlots'], true))
jobs:
- deployment: DeployBackendStaging
displayName: 'Deploy Backend to Staging'
environment: 'staging'
strategy:
runOnce:
deploy:
steps:
- task: AzureWebAppContainer@1
displayName: 'Deploy Backend to Staging Slot'
inputs:
azureSubscription: '$(azureSubscription)'
appName: '$(backendAppName)'
deployToSlotOrASE: true
resourceGroupName: '$(resourceGroup)'
slotName: '$(stagingSlotName)'
containers: '$(acrName).azurecr.io/$(repositoryName)/backend:latest'
- task: AzureCLI@2
displayName: 'Wait for Backend Staging to be Ready'
inputs:
azureSubscription: '$(azureSubscription)'
scriptType: 'bash'
scriptLocation: 'inlineScript'
inlineScript: |
echo "Waiting for backend staging to be ready..."
sleep 30
STAGING_URL="https://$(backendAppName)-$(stagingSlotName).azurewebsites.net/api/health"
for i in {1..10}; do
STATUS=$(curl -s -o /dev/null -w "%{http_code}" $STAGING_URL || echo "000")
if [ "$STATUS" = "200" ]; then
echo "✅ Backend staging is ready"
exit 0
fi
echo "Waiting... ($i/10)"
sleep 10
done
echo "⚠️ Backend staging health check timeout"
- deployment: DeployFrontendStaging
displayName: 'Deploy Frontend to Staging'
environment: 'staging'
strategy:
runOnce:
deploy:
steps:
- task: AzureWebAppContainer@1
displayName: 'Deploy Frontend to Staging Slot'
inputs:
azureSubscription: '$(azureSubscription)'
appName: '$(frontendAppName)'
deployToSlotOrASE: true
resourceGroupName: '$(resourceGroup)'
slotName: '$(stagingSlotName)'
containers: '$(acrName).azurecr.io/$(repositoryName)/frontend:latest'
- task: AzureCLI@2
displayName: 'Wait for Frontend Staging to be Ready'
inputs:
azureSubscription: '$(azureSubscription)'
scriptType: 'bash'
scriptLocation: 'inlineScript'
inlineScript: |
echo "Waiting for frontend staging to be ready..."
sleep 20
STAGING_URL="https://$(frontendAppName)-$(stagingSlotName).azurewebsites.net"
for i in {1..10}; do
STATUS=$(curl -s -o /dev/null -w "%{http_code}" $STAGING_URL || echo "000")
if [ "$STATUS" = "200" ]; then
echo "✅ Frontend staging is ready"
exit 0
fi
echo "Waiting... ($i/10)"
sleep 10
done
echo "⚠️ Frontend staging health check timeout"
- stage: SwapToProduction
displayName: 'Swap Staging to Production'
dependsOn: DeployToStaging
condition: and(succeeded(), eq(variables['deployToProduction'], true), eq(variables['useDeploymentSlots'], true))
jobs:
- deployment: SwapBackend
displayName: 'Swap Backend to Production'
environment: 'production'
strategy:
runOnce:
deploy:
steps:
- task: AzureCLI@2
displayName: 'Swap Backend Staging to Production'
inputs:
azureSubscription: '$(azureSubscription)'
scriptType: 'bash'
scriptLocation: 'inlineScript'
inlineScript: |
echo "Swapping backend staging to production..."
az webapp deployment slot swap \
--name $(backendAppName) \
--resource-group $(resourceGroup) \
--slot $(stagingSlotName) \
--target-slot production
echo "✅ Backend swapped to production"
- deployment: SwapFrontend
displayName: 'Swap Frontend to Production'
environment: 'production'
strategy:
runOnce:
deploy:
steps:
- task: AzureCLI@2
displayName: 'Swap Frontend Staging to Production'
inputs:
azureSubscription: '$(azureSubscription)'
scriptType: 'bash'
scriptLocation: 'inlineScript'
inlineScript: |
echo "Swapping frontend staging to production..."
az webapp deployment slot swap \
--name $(frontendAppName) \
--resource-group $(resourceGroup) \
--slot $(stagingSlotName) \
--target-slot production
echo "✅ Frontend swapped to production"
- stage: VerifyProduction
displayName: 'Verify Production Deployment'
dependsOn: SwapToProduction
condition: and(succeeded(), eq(variables['deployToProduction'], true), eq(variables['useDeploymentSlots'], true))
jobs:
- job: VerifyDeployment
displayName: 'Verify Production'
steps:
- task: AzureCLI@2
displayName: 'Production Health Check'
inputs:
azureSubscription: '$(azureSubscription)'
scriptType: 'bash'
scriptLocation: 'inlineScript'
inlineScript: |
echo "Verifying production deployment..."
BACKEND_URL="https://$(backendAppName).azurewebsites.net/api/health"
FRONTEND_URL="https://$(frontendAppName).azurewebsites.net"
echo "Backend URL: $BACKEND_URL"
echo "Frontend URL: $FRONTEND_URL"
# Wait for swap to complete
sleep 15
# Check backend health
BACKEND_STATUS=$(curl -s -o /dev/null -w "%{http_code}" $BACKEND_URL || echo "000")
if [ "$BACKEND_STATUS" = "200" ]; then
echo "✅ Backend production health check passed"
else
echo "❌ Backend production health check failed: $BACKEND_STATUS"
exit 1
fi
# Check frontend
FRONTEND_STATUS=$(curl -s -o /dev/null -w "%{http_code}" $FRONTEND_URL || echo "000")
if [ "$FRONTEND_STATUS" = "200" ]; then
echo "✅ Frontend production is accessible"
else
echo "❌ Frontend production check failed: $FRONTEND_STATUS"
exit 1
fi
echo "🎉 Production deployment verified successfully!"