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:
247
azure-pipelines-slots.yml
Normal file
247
azure-pipelines-slots.yml
Normal 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!"
|
||||
Reference in New Issue
Block a user