252 lines
7.6 KiB
YAML
252 lines
7.6 KiB
YAML
trigger:
|
|
branches:
|
|
include:
|
|
- main
|
|
- develop
|
|
paths:
|
|
include:
|
|
- src/*
|
|
- templates/*
|
|
- requirements.txt
|
|
- Dockerfile
|
|
- config.json
|
|
- main.py
|
|
|
|
pr:
|
|
branches:
|
|
include:
|
|
- main
|
|
paths:
|
|
include:
|
|
- src/*
|
|
- templates/*
|
|
- requirements.txt
|
|
- Dockerfile
|
|
- config.json
|
|
- main.py
|
|
|
|
variables:
|
|
# Container registry service connection
|
|
dockerRegistryServiceConnection: 'dock-ptslondon-connection'
|
|
imageRepository: 'price-tracker'
|
|
containerRegistry: 'dock.ptslondon.co.uk'
|
|
dockerfilePath: '$(Build.SourcesDirectory)/Dockerfile'
|
|
|
|
# Agent VM image name
|
|
vmImageName: 'ubuntu-latest'
|
|
|
|
stages:
|
|
- stage: Build
|
|
displayName: 'Build and Test'
|
|
jobs:
|
|
- job: Build
|
|
displayName: 'Build Docker Image'
|
|
pool:
|
|
vmImage: $(vmImageName)
|
|
variables:
|
|
tag: '$(Build.BuildId)'
|
|
steps:
|
|
- checkout: self
|
|
displayName: 'Checkout source code'
|
|
|
|
- task: Docker@2
|
|
displayName: 'Build Docker image'
|
|
inputs:
|
|
command: 'build'
|
|
repository: $(imageRepository)
|
|
dockerfile: $(dockerfilePath)
|
|
tags: |
|
|
$(tag)
|
|
latest
|
|
|
|
- script: |
|
|
echo "Running container tests..."
|
|
# Start container for testing
|
|
docker run -d --name price-tracker-test -p 5000:5000 $(imageRepository):$(tag)
|
|
|
|
# Wait for container to be ready
|
|
echo "Waiting for container to start..."
|
|
for i in {1..30}; do
|
|
if curl -f http://localhost:5000/ > /dev/null 2>&1; then
|
|
echo "Container is ready!"
|
|
break
|
|
fi
|
|
echo "Waiting... ($i/30)"
|
|
sleep 2
|
|
done
|
|
|
|
# Run basic health checks
|
|
echo "Running health checks..."
|
|
curl -f http://localhost:5000/ || (echo "Health check failed" && exit 1)
|
|
|
|
# Cleanup
|
|
docker stop price-tracker-test
|
|
docker rm price-tracker-test
|
|
|
|
echo "All tests passed!"
|
|
displayName: 'Test Docker container'
|
|
|
|
- task: Docker@2
|
|
displayName: 'Push to registry'
|
|
inputs:
|
|
command: 'push'
|
|
repository: $(imageRepository)
|
|
containerRegistry: $(dockerRegistryServiceConnection)
|
|
tags: |
|
|
$(tag)
|
|
latest
|
|
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'))
|
|
|
|
- stage: SecurityScan
|
|
displayName: 'Security Scanning'
|
|
dependsOn: Build
|
|
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'))
|
|
jobs:
|
|
- job: VulnerabilityScan
|
|
displayName: 'Vulnerability Scan'
|
|
pool:
|
|
vmImage: $(vmImageName)
|
|
variables:
|
|
tag: '$(Build.BuildId)'
|
|
steps:
|
|
- task: Docker@2
|
|
displayName: 'Pull image for scanning'
|
|
inputs:
|
|
command: 'pull'
|
|
arguments: '$(containerRegistry)/$(imageRepository):$(tag)'
|
|
containerRegistry: $(dockerRegistryServiceConnection)
|
|
|
|
- script: |
|
|
# Install Trivy
|
|
sudo apt-get update
|
|
sudo apt-get install wget apt-transport-https gnupg lsb-release -y
|
|
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add -
|
|
echo "deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main" | sudo tee -a /etc/apt/sources.list.d/trivy.list
|
|
sudo apt-get update
|
|
sudo apt-get install trivy -y
|
|
|
|
# Run vulnerability scan
|
|
trivy image --exit-code 0 --severity LOW,MEDIUM --format table $(containerRegistry)/$(imageRepository):$(tag)
|
|
trivy image --exit-code 1 --severity HIGH,CRITICAL --format table $(containerRegistry)/$(imageRepository):$(tag)
|
|
displayName: 'Run Trivy vulnerability scan'
|
|
continueOnError: true
|
|
|
|
- stage: DeployDev
|
|
displayName: 'Deploy to Development'
|
|
dependsOn:
|
|
- Build
|
|
- SecurityScan
|
|
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/develop'))
|
|
jobs:
|
|
- deployment: DeployToDev
|
|
displayName: 'Deploy to Development Environment'
|
|
environment: 'price-tracker-dev'
|
|
pool:
|
|
vmImage: $(vmImageName)
|
|
variables:
|
|
tag: '$(Build.BuildId)'
|
|
strategy:
|
|
runOnce:
|
|
deploy:
|
|
steps:
|
|
- checkout: self
|
|
|
|
- task: Docker@2
|
|
displayName: 'Pull latest image'
|
|
inputs:
|
|
command: 'pull'
|
|
arguments: '$(containerRegistry)/$(imageRepository):$(tag)'
|
|
containerRegistry: $(dockerRegistryServiceConnection)
|
|
|
|
- script: |
|
|
# Create deployment directory
|
|
mkdir -p ~/price-tracker-deployment
|
|
cd ~/price-tracker-deployment
|
|
|
|
# Copy deployment files
|
|
cp $(Pipeline.Workspace)/s/docker-compose.yml .
|
|
cp $(Pipeline.Workspace)/s/config.json .
|
|
|
|
# Update image tag in docker-compose
|
|
sed -i "s/price-tracker:latest/$(containerRegistry)\/$(imageRepository):$(tag)/g" docker-compose.yml
|
|
|
|
# Deploy using docker-compose
|
|
docker-compose down || true
|
|
docker-compose up -d
|
|
|
|
# Wait for deployment
|
|
sleep 10
|
|
|
|
# Verify deployment
|
|
curl -f http://localhost:5000/ || (echo "Deployment verification failed" && exit 1)
|
|
|
|
echo "Deployment to development completed successfully!"
|
|
displayName: 'Deploy to development'
|
|
|
|
- stage: DeployProd
|
|
displayName: 'Deploy to Production'
|
|
dependsOn:
|
|
- Build
|
|
- SecurityScan
|
|
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
|
|
jobs:
|
|
- deployment: DeployToProd
|
|
displayName: 'Deploy to Production Environment'
|
|
environment: 'price-tracker-prod'
|
|
pool:
|
|
vmImage: $(vmImageName)
|
|
variables:
|
|
tag: '$(Build.BuildId)'
|
|
strategy:
|
|
runOnce:
|
|
deploy:
|
|
steps:
|
|
- checkout: self
|
|
|
|
- task: Docker@2
|
|
displayName: 'Pull latest image'
|
|
inputs:
|
|
command: 'pull'
|
|
arguments: '$(containerRegistry)/$(imageRepository):$(tag)'
|
|
containerRegistry: $(dockerRegistryServiceConnection)
|
|
|
|
- script: |
|
|
# Production deployment script
|
|
echo "Deploying to production..."
|
|
|
|
# Create deployment directory
|
|
mkdir -p ~/price-tracker-production
|
|
cd ~/price-tracker-production
|
|
|
|
# Copy deployment files
|
|
cp $(Pipeline.Workspace)/s/docker-compose.yml .
|
|
cp $(Pipeline.Workspace)/s/config.json .
|
|
|
|
# Update image tag in docker-compose for production
|
|
sed -i "s/price-tracker:latest/$(containerRegistry)\/$(imageRepository):$(tag)/g" docker-compose.yml
|
|
|
|
# Production-specific environment settings
|
|
export FLASK_ENV=production
|
|
|
|
# Deploy with zero-downtime strategy
|
|
docker-compose pull
|
|
docker-compose up -d
|
|
|
|
# Health check
|
|
sleep 15
|
|
for i in {1..10}; do
|
|
if curl -f http://localhost:5000/; then
|
|
echo "Production deployment successful!"
|
|
break
|
|
fi
|
|
echo "Waiting for production deployment... ($i/10)"
|
|
sleep 5
|
|
done
|
|
displayName: 'Deploy to production'
|
|
|
|
- script: |
|
|
# Post-deployment notifications (optional)
|
|
echo "Production deployment completed at $(date)"
|
|
# You can add notification webhooks here
|
|
displayName: 'Post-deployment tasks'
|