- 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
248 lines
8.9 KiB
YAML
248 lines
8.9 KiB
YAML
# 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!"
|