mirror of
https://github.com/BagelHole/DevOps-Security-Agent-Skills.git
synced 2026-08-22 12:49:53 +02:00
502 lines
12 KiB
Markdown
502 lines
12 KiB
Markdown
---
|
|||
|
|
name: blue-green-deploy
|
||
|
|
description: Configure zero-downtime deployment strategies including blue-green, canary, and rolling deployments. Implement traffic shifting, health checks, and rollback procedures. Use when implementing production deployment strategies or zero-downtime releases.
|
||
|
|
license: MIT
|
||
|
|
metadata:
|
||
|
|
author: devops-skills
|
||
|
|
version: "1.0"
|
||
|
|
---
|
||
|
|
|
||
|
|
# Blue-Green & Deployment Strategies
|
||
|
|
|
||
|
|
Implement zero-downtime deployment patterns for production systems.
|
||
|
|
|
||
|
|
## When to Use This Skill
|
||
|
|
|
||
|
|
Use this skill when:
|
||
|
|
- Implementing zero-downtime deployments
|
||
|
|
- Reducing deployment risk
|
||
|
|
- Enabling instant rollbacks
|
||
|
|
- Running canary releases
|
||
|
|
- Performing A/B testing in production
|
||
|
|
|
||
|
|
## Prerequisites
|
||
|
|
|
||
|
|
- Load balancer or ingress controller
|
||
|
|
- Container orchestration (K8s) or cloud platform
|
||
|
|
- CI/CD pipeline
|
||
|
|
- Health check endpoints
|
||
|
|
|
||
|
|
## Deployment Strategy Overview
|
||
|
|
|
||
|
|
```
|
||
|
|
┌─────────────────────────────────────────────────────────────┐
|
||
|
|
│ DEPLOYMENT STRATEGIES │
|
||
|
|
├─────────────┬─────────────┬─────────────┬──────────────────┤
|
||
|
|
│ Blue-Green │ Canary │ Rolling │ Recreate │
|
||
|
|
├─────────────┼─────────────┼─────────────┼──────────────────┤
|
||
|
|
│ Full env │ Gradual % │ Pod by pod │ All at once │
|
||
|
|
│ swap │ rollout │ replacement │ │
|
||
|
|
├─────────────┼─────────────┼─────────────┼──────────────────┤
|
||
|
|
│ Instant │ Slow, safe │ Moderate │ Fast, risky │
|
||
|
|
│ rollback │ rollback │ rollback │ │
|
||
|
|
├─────────────┼─────────────┼─────────────┼──────────────────┤
|
||
|
|
│ 2x resources│ +10-25% │ Same │ Same │
|
||
|
|
│ needed │ resources │ resources │ │
|
||
|
|
└─────────────┴─────────────┴─────────────┴──────────────────┘
|
||
|
|
```
|
||
|
|
|
||
|
|
## Blue-Green Deployment
|
||
|
|
|
||
|
|
### Concept
|
||
|
|
|
||
|
|
```
|
||
|
|
Before:
|
||
|
|
┌─────────┐ ┌───────────────┐
|
||
|
|
│ Users │────▶│ Blue (v1) │ ◀── Active
|
||
|
|
└─────────┘ └───────────────┘
|
||
|
|
┌───────────────┐
|
||
|
|
│ Green (v2) │ ◀── Staging
|
||
|
|
└───────────────┘
|
||
|
|
|
||
|
|
After Switch:
|
||
|
|
┌─────────┐ ┌───────────────┐
|
||
|
|
│ Users │ │ Blue (v1) │ ◀── Standby
|
||
|
|
└─────────┘ └───────────────┘
|
||
|
|
│ ┌───────────────┐
|
||
|
|
└────────▶│ Green (v2) │ ◀── Active
|
||
|
|
└───────────────┘
|
||
|
|
```
|
||
|
|
|
||
|
|
### Kubernetes Implementation
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
# blue-deployment.yaml
|
||
|
|
apiVersion: apps/v1
|
||
|
|
kind: Deployment
|
||
|
|
metadata:
|
||
|
|
name: myapp-blue
|
||
|
|
labels:
|
||
|
|
app: myapp
|
||
|
|
version: blue
|
||
|
|
spec:
|
||
|
|
replicas: 3
|
||
|
|
selector:
|
||
|
|
matchLabels:
|
||
|
|
app: myapp
|
||
|
|
version: blue
|
||
|
|
template:
|
||
|
|
metadata:
|
||
|
|
labels:
|
||
|
|
app: myapp
|
||
|
|
version: blue
|
||
|
|
spec:
|
||
|
|
containers:
|
||
|
|
- name: myapp
|
||
|
|
image: myapp:v1.0.0
|
||
|
|
ports:
|
||
|
|
- containerPort: 8080
|
||
|
|
readinessProbe:
|
||
|
|
httpGet:
|
||
|
|
path: /health
|
||
|
|
port: 8080
|
||
|
|
initialDelaySeconds: 5
|
||
|
|
periodSeconds: 5
|
||
|
|
---
|
||
|
|
# green-deployment.yaml
|
||
|
|
apiVersion: apps/v1
|
||
|
|
kind: Deployment
|
||
|
|
metadata:
|
||
|
|
name: myapp-green
|
||
|
|
labels:
|
||
|
|
app: myapp
|
||
|
|
version: green
|
||
|
|
spec:
|
||
|
|
replicas: 3
|
||
|
|
selector:
|
||
|
|
matchLabels:
|
||
|
|
app: myapp
|
||
|
|
version: green
|
||
|
|
template:
|
||
|
|
metadata:
|
||
|
|
labels:
|
||
|
|
app: myapp
|
||
|
|
version: green
|
||
|
|
spec:
|
||
|
|
containers:
|
||
|
|
- name: myapp
|
||
|
|
image: myapp:v2.0.0
|
||
|
|
ports:
|
||
|
|
- containerPort: 8080
|
||
|
|
readinessProbe:
|
||
|
|
httpGet:
|
||
|
|
path: /health
|
||
|
|
port: 8080
|
||
|
|
initialDelaySeconds: 5
|
||
|
|
periodSeconds: 5
|
||
|
|
---
|
||
|
|
# service.yaml - Switch by changing selector
|
||
|
|
apiVersion: v1
|
||
|
|
kind: Service
|
||
|
|
metadata:
|
||
|
|
name: myapp
|
||
|
|
spec:
|
||
|
|
selector:
|
||
|
|
app: myapp
|
||
|
|
version: blue # Change to 'green' to switch
|
||
|
|
ports:
|
||
|
|
- port: 80
|
||
|
|
targetPort: 8080
|
||
|
|
```
|
||
|
|
|
||
|
|
### Switch Script
|
||
|
|
|
||
|
|
```bash
|
||
|
|
#!/bin/bash
|
||
|
|
# blue-green-switch.sh
|
||
|
|
|
||
|
|
CURRENT=$(kubectl get svc myapp -o jsonpath='{.spec.selector.version}')
|
||
|
|
NEW_VERSION=$1
|
||
|
|
|
||
|
|
echo "Current version: $CURRENT"
|
||
|
|
echo "Switching to: $NEW_VERSION"
|
||
|
|
|
||
|
|
# Verify new deployment is ready
|
||
|
|
kubectl rollout status deployment/myapp-$NEW_VERSION
|
||
|
|
|
||
|
|
# Check health
|
||
|
|
HEALTH=$(kubectl exec -it deployment/myapp-$NEW_VERSION -- curl -s localhost:8080/health)
|
||
|
|
if [ "$HEALTH" != "ok" ]; then
|
||
|
|
echo "Health check failed"
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
|
||
|
|
# Switch traffic
|
||
|
|
kubectl patch svc myapp -p "{\"spec\":{\"selector\":{\"version\":\"$NEW_VERSION\"}}}"
|
||
|
|
|
||
|
|
echo "Switched to $NEW_VERSION"
|
||
|
|
```
|
||
|
|
|
||
|
|
### AWS ECS Blue-Green
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
# AWS CodeDeploy appspec.yml
|
||
|
|
version: 0.0
|
||
|
|
Resources:
|
||
|
|
- TargetService:
|
||
|
|
Type: AWS::ECS::Service
|
||
|
|
Properties:
|
||
|
|
TaskDefinition: "arn:aws:ecs:region:account:task-definition/myapp:2"
|
||
|
|
LoadBalancerInfo:
|
||
|
|
ContainerName: "myapp"
|
||
|
|
ContainerPort: 8080
|
||
|
|
Hooks:
|
||
|
|
- BeforeInstall: "LambdaFunctionToValidateBeforeTrafficShift"
|
||
|
|
- AfterInstall: "LambdaFunctionToValidateAfterTrafficShift"
|
||
|
|
- AfterAllowTestTraffic: "LambdaFunctionToValidateTestTraffic"
|
||
|
|
- BeforeAllowTraffic: "LambdaFunctionToValidateBeforeAllowTraffic"
|
||
|
|
- AfterAllowTraffic: "LambdaFunctionToValidateAfterAllowTraffic"
|
||
|
|
```
|
||
|
|
|
||
|
|
## Canary Deployment
|
||
|
|
|
||
|
|
### Kubernetes with Istio
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
# VirtualService for traffic splitting
|
||
|
|
apiVersion: networking.istio.io/v1beta1
|
||
|
|
kind: VirtualService
|
||
|
|
metadata:
|
||
|
|
name: myapp
|
||
|
|
spec:
|
||
|
|
hosts:
|
||
|
|
- myapp
|
||
|
|
http:
|
||
|
|
- match:
|
||
|
|
- headers:
|
||
|
|
x-canary:
|
||
|
|
exact: "true"
|
||
|
|
route:
|
||
|
|
- destination:
|
||
|
|
host: myapp
|
||
|
|
subset: canary
|
||
|
|
- route:
|
||
|
|
- destination:
|
||
|
|
host: myapp
|
||
|
|
subset: stable
|
||
|
|
weight: 90
|
||
|
|
- destination:
|
||
|
|
host: myapp
|
||
|
|
subset: canary
|
||
|
|
weight: 10
|
||
|
|
---
|
||
|
|
apiVersion: networking.istio.io/v1beta1
|
||
|
|
kind: DestinationRule
|
||
|
|
metadata:
|
||
|
|
name: myapp
|
||
|
|
spec:
|
||
|
|
host: myapp
|
||
|
|
subsets:
|
||
|
|
- name: stable
|
||
|
|
labels:
|
||
|
|
version: stable
|
||
|
|
- name: canary
|
||
|
|
labels:
|
||
|
|
version: canary
|
||
|
|
```
|
||
|
|
|
||
|
|
### Argo Rollouts
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
apiVersion: argoproj.io/v1alpha1
|
||
|
|
kind: Rollout
|
||
|
|
metadata:
|
||
|
|
name: myapp
|
||
|
|
spec:
|
||
|
|
replicas: 5
|
||
|
|
strategy:
|
||
|
|
canary:
|
||
|
|
steps:
|
||
|
|
- setWeight: 10
|
||
|
|
- pause: {duration: 5m}
|
||
|
|
- setWeight: 25
|
||
|
|
- pause: {duration: 5m}
|
||
|
|
- setWeight: 50
|
||
|
|
- pause: {duration: 5m}
|
||
|
|
- setWeight: 75
|
||
|
|
- pause: {duration: 5m}
|
||
|
|
analysis:
|
||
|
|
templates:
|
||
|
|
- templateName: success-rate
|
||
|
|
startingStep: 2
|
||
|
|
args:
|
||
|
|
- name: service-name
|
||
|
|
value: myapp
|
||
|
|
selector:
|
||
|
|
matchLabels:
|
||
|
|
app: myapp
|
||
|
|
template:
|
||
|
|
metadata:
|
||
|
|
labels:
|
||
|
|
app: myapp
|
||
|
|
spec:
|
||
|
|
containers:
|
||
|
|
- name: myapp
|
||
|
|
image: myapp:v2.0.0
|
||
|
|
ports:
|
||
|
|
- containerPort: 8080
|
||
|
|
---
|
||
|
|
apiVersion: argoproj.io/v1alpha1
|
||
|
|
kind: AnalysisTemplate
|
||
|
|
metadata:
|
||
|
|
name: success-rate
|
||
|
|
spec:
|
||
|
|
args:
|
||
|
|
- name: service-name
|
||
|
|
metrics:
|
||
|
|
- name: success-rate
|
||
|
|
interval: 1m
|
||
|
|
successCondition: result[0] >= 0.95
|
||
|
|
failureLimit: 3
|
||
|
|
provider:
|
||
|
|
prometheus:
|
||
|
|
address: http://prometheus:9090
|
||
|
|
query: |
|
||
|
|
sum(rate(http_requests_total{service="{{args.service-name}}",status=~"2.*"}[5m]))
|
||
|
|
/
|
||
|
|
sum(rate(http_requests_total{service="{{args.service-name}}"}[5m]))
|
||
|
|
```
|
||
|
|
|
||
|
|
## Rolling Deployment
|
||
|
|
|
||
|
|
### Kubernetes Default
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
apiVersion: apps/v1
|
||
|
|
kind: Deployment
|
||
|
|
metadata:
|
||
|
|
name: myapp
|
||
|
|
spec:
|
||
|
|
replicas: 5
|
||
|
|
strategy:
|
||
|
|
type: RollingUpdate
|
||
|
|
rollingUpdate:
|
||
|
|
maxSurge: 1 # Max pods above desired
|
||
|
|
maxUnavailable: 0 # Max pods unavailable
|
||
|
|
selector:
|
||
|
|
matchLabels:
|
||
|
|
app: myapp
|
||
|
|
template:
|
||
|
|
metadata:
|
||
|
|
labels:
|
||
|
|
app: myapp
|
||
|
|
spec:
|
||
|
|
containers:
|
||
|
|
- name: myapp
|
||
|
|
image: myapp:v2.0.0
|
||
|
|
ports:
|
||
|
|
- containerPort: 8080
|
||
|
|
readinessProbe:
|
||
|
|
httpGet:
|
||
|
|
path: /ready
|
||
|
|
port: 8080
|
||
|
|
initialDelaySeconds: 5
|
||
|
|
periodSeconds: 5
|
||
|
|
livenessProbe:
|
||
|
|
httpGet:
|
||
|
|
path: /health
|
||
|
|
port: 8080
|
||
|
|
initialDelaySeconds: 10
|
||
|
|
periodSeconds: 10
|
||
|
|
```
|
||
|
|
|
||
|
|
### Rolling Update Commands
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Update image
|
||
|
|
kubectl set image deployment/myapp myapp=myapp:v2.0.0
|
||
|
|
|
||
|
|
# Watch rollout
|
||
|
|
kubectl rollout status deployment/myapp
|
||
|
|
|
||
|
|
# Pause rollout
|
||
|
|
kubectl rollout pause deployment/myapp
|
||
|
|
|
||
|
|
# Resume rollout
|
||
|
|
kubectl rollout resume deployment/myapp
|
||
|
|
|
||
|
|
# Rollback
|
||
|
|
kubectl rollout undo deployment/myapp
|
||
|
|
|
||
|
|
# Rollback to specific revision
|
||
|
|
kubectl rollout undo deployment/myapp --to-revision=2
|
||
|
|
|
||
|
|
# View history
|
||
|
|
kubectl rollout history deployment/myapp
|
||
|
|
```
|
||
|
|
|
||
|
|
## Health Checks
|
||
|
|
|
||
|
|
### Comprehensive Health Endpoint
|
||
|
|
|
||
|
|
```python
|
||
|
|
# Flask health endpoint
|
||
|
|
from flask import Flask, jsonify
|
||
|
|
import psycopg2
|
||
|
|
import redis
|
||
|
|
|
||
|
|
app = Flask(__name__)
|
||
|
|
|
||
|
|
@app.route('/health')
|
||
|
|
def health():
|
||
|
|
"""Liveness probe - is the app running?"""
|
||
|
|
return jsonify({'status': 'healthy'}), 200
|
||
|
|
|
||
|
|
@app.route('/ready')
|
||
|
|
def ready():
|
||
|
|
"""Readiness probe - can the app serve traffic?"""
|
||
|
|
checks = {}
|
||
|
|
|
||
|
|
# Database check
|
||
|
|
try:
|
||
|
|
conn = psycopg2.connect(DATABASE_URL)
|
||
|
|
conn.close()
|
||
|
|
checks['database'] = 'ok'
|
||
|
|
except Exception as e:
|
||
|
|
checks['database'] = str(e)
|
||
|
|
return jsonify({'status': 'unhealthy', 'checks': checks}), 503
|
||
|
|
|
||
|
|
# Redis check
|
||
|
|
try:
|
||
|
|
r = redis.from_url(REDIS_URL)
|
||
|
|
r.ping()
|
||
|
|
checks['redis'] = 'ok'
|
||
|
|
except Exception as e:
|
||
|
|
checks['redis'] = str(e)
|
||
|
|
return jsonify({'status': 'unhealthy', 'checks': checks}), 503
|
||
|
|
|
||
|
|
return jsonify({'status': 'healthy', 'checks': checks}), 200
|
||
|
|
```
|
||
|
|
|
||
|
|
## Rollback Procedures
|
||
|
|
|
||
|
|
### Automated Rollback
|
||
|
|
|
||
|
|
```bash
|
||
|
|
#!/bin/bash
|
||
|
|
# auto-rollback.sh
|
||
|
|
|
||
|
|
DEPLOYMENT=$1
|
||
|
|
THRESHOLD=0.95
|
||
|
|
INTERVAL=60
|
||
|
|
|
||
|
|
echo "Monitoring deployment $DEPLOYMENT"
|
||
|
|
|
||
|
|
while true; do
|
||
|
|
# Get success rate from Prometheus
|
||
|
|
SUCCESS_RATE=$(curl -s "http://prometheus:9090/api/v1/query?query=sum(rate(http_requests_total{status=~\"2.*\"}[5m]))/sum(rate(http_requests_total[5m]))" | jq -r '.data.result[0].value[1]')
|
||
|
|
|
||
|
|
echo "Current success rate: $SUCCESS_RATE"
|
||
|
|
|
||
|
|
if (( $(echo "$SUCCESS_RATE < $THRESHOLD" | bc -l) )); then
|
||
|
|
echo "Success rate below threshold! Rolling back..."
|
||
|
|
kubectl rollout undo deployment/$DEPLOYMENT
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
|
||
|
|
sleep $INTERVAL
|
||
|
|
done
|
||
|
|
```
|
||
|
|
|
||
|
|
### Manual Rollback Checklist
|
||
|
|
|
||
|
|
```markdown
|
||
|
|
## Rollback Checklist
|
||
|
|
|
||
|
|
### Before Rollback
|
||
|
|
- [ ] Confirm issue is deployment-related
|
||
|
|
- [ ] Document current error rates
|
||
|
|
- [ ] Notify team in #deployments channel
|
||
|
|
|
||
|
|
### During Rollback
|
||
|
|
- [ ] Execute rollback command
|
||
|
|
- [ ] Monitor rollback progress
|
||
|
|
- [ ] Verify old version is serving traffic
|
||
|
|
|
||
|
|
### After Rollback
|
||
|
|
- [ ] Confirm error rates normalized
|
||
|
|
- [ ] Update incident ticket
|
||
|
|
- [ ] Schedule post-mortem
|
||
|
|
```
|
||
|
|
|
||
|
|
## Common Issues
|
||
|
|
|
||
|
|
### Issue: Slow Deployments
|
||
|
|
**Problem**: Rollout takes too long
|
||
|
|
**Solution**: Increase maxSurge, decrease minReadySeconds
|
||
|
|
|
||
|
|
### Issue: Failed Health Checks
|
||
|
|
**Problem**: Pods not becoming ready
|
||
|
|
**Solution**: Check probe endpoints, increase timeouts
|
||
|
|
|
||
|
|
### Issue: Traffic During Rollback
|
||
|
|
**Problem**: Errors during switch
|
||
|
|
**Solution**: Use connection draining, implement graceful shutdown
|
||
|
|
|
||
|
|
## Best Practices
|
||
|
|
|
||
|
|
- Always implement health checks
|
||
|
|
- Use connection draining
|
||
|
|
- Test rollback procedures regularly
|
||
|
|
- Monitor key metrics during deployment
|
||
|
|
- Implement circuit breakers
|
||
|
|
- Use deployment slots/environments
|
||
|
|
- Automate deployment verification
|
||
|
|
- Document rollback procedures
|
||
|
|
|
||
|
|
## Related Skills
|
||
|
|
|
||
|
|
- [kubernetes-ops](../../orchestration/kubernetes-ops/) - K8s deployment basics
|
||
|
|
- [argocd-gitops](../../orchestration/argocd-gitops/) - GitOps deployments
|
||
|
|
- [feature-flags](../feature-flags/) - Progressive rollout
|