352 lines
12 KiB
YAML
Raw Permalink Normal View History

2026-01-12 03:36:55 +00:00
# VAPORA Woodpecker Pipeline - Rollback Deployment
# Safe deployment rollback with verification and pre-checks
# Triggers on: manual promotion only (safety feature)
trigger:
event: [promote]
branch: [main, develop]
variables:
ARTIFACTS_DIR: provisioning/artifacts
LOGS_DIR: provisioning/logs
VAPORA_NAMESPACE: vapora
stages:
pre_rollback_checks:
steps:
- name: verify_environment
image: alpine:latest
commands:
- |
echo "🔒 Pre-Rollback Safety Checks"
echo "---"
mkdir -p ${LOGS_DIR}/rollback
{
echo "Rollback initiated at: $(date -u +'%Y-%m-%dT%H:%M:%SZ')"
echo "Commit: ${CI_COMMIT_SHA:0:8}"
echo "Branch: ${CI_COMMIT_BRANCH}"
echo "Pipeline: ${CI_BUILD_LINK}"
echo ""
echo "⚠️ This action will rollback production systems!"
echo " Ensure this is intentional and approved."
} | tee ${LOGS_DIR}/rollback/pre-rollback-snapshot.txt
install_dependencies:
depends_on: [pre_rollback_checks]
steps:
- name: install_tools
image: rust:latest
commands:
- apt-get update && apt-get install -y curl jq yq
- cargo install nu --locked
- pip install jinja2-cli
- curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
- chmod +x kubectl && mv kubectl /usr/local/bin/
- nu --version
- kubectl version --client
- yq --version
configure_kubernetes:
depends_on: [install_dependencies]
steps:
- name: setup_kubeconfig
image: alpine:latest
environment:
KUBE_CONFIG_STAGING: ${KUBE_CONFIG_STAGING}
KUBE_CONFIG_PRODUCTION: ${KUBE_CONFIG_PRODUCTION}
commands:
- mkdir -p ~/.kube
- |
if [ "${Rollback_Environment}" = "production" ]; then
echo "$KUBE_CONFIG_PRODUCTION" | base64 -d > ~/.kube/config
echo "✓ Production kubeconfig configured"
else
echo "$KUBE_CONFIG_STAGING" | base64 -d > ~/.kube/config
echo "✓ Staging kubeconfig configured"
fi
- chmod 600 ~/.kube/config
- kubectl cluster-info
- kubectl get nodes
store_deployment_history:
depends_on: [configure_kubernetes]
steps:
- name: snapshot_current_state
image: alpine:latest
commands:
- apk add --no-cache curl
- |
echo "📸 Storing current deployment history..."
mkdir -p ${LOGS_DIR}/rollback
{
echo "=== Current Deployment State ===" | tee ${LOGS_DIR}/rollback/pre-rollback-status.txt
echo ""
echo "Deployments:"
kubectl get deployments -n ${VAPORA_NAMESPACE} -o yaml | tee -a ${LOGS_DIR}/rollback/pre-rollback-status.txt
echo ""
echo "Rollout History:"
for deployment in vapora-backend vapora-agents vapora-llm-router; do
echo "--- $deployment ---" | tee -a ${LOGS_DIR}/rollback/pre-rollback-status.txt
kubectl rollout history deployment/$deployment -n ${VAPORA_NAMESPACE} 2>&1 | tee -a ${LOGS_DIR}/rollback/pre-rollback-status.txt
done
}
kubernetes_rollback:
depends_on: [store_deployment_history]
steps:
- name: perform_rollback
image: rust:latest
environment:
RUST_LOG: warn
commands:
- apt-get update && apt-get install -y curl jq
- |
echo "🔙 Performing Kubernetes Rollback..."
mkdir -p ${LOGS_DIR}/rollback
cd provisioning
nu scripts/rollback.nu \
--target kubernetes \
--deployment "${Rollback_Deployment:-all}" \
--revision ${Rollback_Revision:-0} \
2>&1 | tee ../${LOGS_DIR}/rollback/rollback-output.log
- name: verify_rollback
image: alpine:latest
commands:
- apk add --no-cache curl
- |
echo "✓ Verifying rollback status..."
{
echo "=== Post-Rollback Deployment State ===" | tee ${LOGS_DIR}/rollback/post-rollback-status.txt
echo ""
echo "Deployments:"
kubectl get deployments -n ${VAPORA_NAMESPACE} -o wide | tee -a ${LOGS_DIR}/rollback/post-rollback-status.txt
echo ""
echo "Rollout Status:"
for deployment in vapora-backend vapora-agents vapora-llm-router; do
echo "--- $deployment ---" | tee -a ${LOGS_DIR}/rollback/post-rollback-status.txt
kubectl rollout status deployment/$deployment -n ${VAPORA_NAMESPACE} --timeout=5m 2>&1 | tee -a ${LOGS_DIR}/rollback/post-rollback-status.txt
done
}
- name: check_pod_health
image: alpine:latest
commands:
- apk add --no-cache curl
- |
echo "Pod Status After Rollback:" | tee -a ${LOGS_DIR}/rollback/post-rollback-status.txt
kubectl get pods -n ${VAPORA_NAMESPACE} -o wide | tee -a ${LOGS_DIR}/rollback/post-rollback-status.txt
echo "" | tee -a ${LOGS_DIR}/rollback/post-rollback-status.txt
echo "Recent Events:" | tee -a ${LOGS_DIR}/rollback/post-rollback-status.txt
kubectl get events -n ${VAPORA_NAMESPACE} --sort-by='.lastTimestamp' | tail -20 | tee -a ${LOGS_DIR}/rollback/post-rollback-status.txt
docker_rollback_guide:
depends_on: [store_deployment_history]
steps:
- name: generate_docker_guide
image: alpine:latest
commands:
- |
echo "📝 Generating Docker rollback guide..."
mkdir -p ${LOGS_DIR}/rollback
cat > ${LOGS_DIR}/rollback/DOCKER_ROLLBACK_GUIDE.md << 'EOF'
# Docker Rollback Guide
Docker Compose rollback requires manual steps:
## Option 1: Revert to previous compose file
```bash
cd deploy/docker
docker compose down
git checkout HEAD~1 docker-compose.yml
docker compose up -d
```
## Option 2: Stop and restart with older images
```bash
docker compose -f docker-compose.yml.backup up -d
```
## Option 3: Remove containers and redeploy from previous artifacts
```bash
docker compose down
docker system prune -f
docker compose up -d
```
## Verification
After rollback, verify services are running:
```bash
docker compose ps
docker compose logs -f backend
curl http://localhost:8001/health
```
## Checking Compose File Backups
```bash
find . -name "docker-compose*.yml*" -type f | sort
```
## Restoring from Backup
```bash
# If you have a timestamped backup
cp docker-compose.yml.$(date +%s) docker-compose.yml
docker compose up -d
```
EOF
cat ${LOGS_DIR}/rollback/DOCKER_ROLLBACK_GUIDE.md
- name: store_docker_state
image: alpine:latest
commands:
- |
echo "📋 Storing Docker Compose state..."
mkdir -p ${LOGS_DIR}/rollback
if [ -f "deploy/docker/docker-compose.yml" ]; then
cp deploy/docker/docker-compose.yml ${LOGS_DIR}/rollback/current-docker-compose.yml
echo "✓ Current docker-compose.yml backed up"
fi
echo "Looking for available backups..."
find . -name "docker-compose*.yml*" -type f 2>/dev/null | head -20 | tee ${LOGS_DIR}/rollback/available-backups.txt
post_rollback_verification:
depends_on: [kubernetes_rollback, docker_rollback_guide]
steps:
- name: generate_rollback_report
image: alpine:latest
commands:
- |
mkdir -p ${LOGS_DIR}/rollback
cat > ${LOGS_DIR}/rollback/ROLLBACK_REPORT.md << 'EOF'
# Rollback Execution Report
**Rollback Time**: $(date -u +'%Y-%m-%dT%H:%M:%SZ')
**Target**: ${Rollback_Target:-kubernetes}
**Environment**: ${Rollback_Environment:-staging}
**Deployment**: ${Rollback_Deployment:-all}
**Revision**: ${Rollback_Revision:-0 (previous)}
**Pipeline**: ${CI_BUILD_LINK}
## Status
- **Pre-rollback Checks**: ✅ Passed
- **Rollback Execution**: In Progress
- **Post-rollback Verification**: Pending
## Artifacts
Check the following for detailed information:
- `pre-rollback-snapshot.txt` - Initial state snapshot
- `pre-rollback-status.txt` - Pre-rollback deployments
- `post-rollback-status.txt` - Post-rollback status
- `rollback-output.log` - Rollback script output
- `DOCKER_ROLLBACK_GUIDE.md` - Docker rollback instructions (if applicable)
## Next Steps
1. Verify all services are running
2. Check application logs for errors
3. Run health checks
4. Monitor metrics and alerts
5. Investigate root cause of previous deployment failure
6. Plan corrected deployment
## Rollback Verification Commands
### For Kubernetes
```bash
# Check current deployments
kubectl get deployments -n ${VAPORA_NAMESPACE}
kubectl get pods -n ${VAPORA_NAMESPACE}
# View logs
kubectl logs -f deployment/vapora-backend -n ${VAPORA_NAMESPACE}
# Check rollout history
kubectl rollout history deployment/vapora-backend -n ${VAPORA_NAMESPACE}
# View recent events
kubectl get events -n ${VAPORA_NAMESPACE} --sort-by='.lastTimestamp'
```
### For Docker
```bash
# Check container status
docker compose ps
# View logs
docker compose logs -f
# Check service health
curl http://localhost:8001/health
```
EOF
cat ${LOGS_DIR}/rollback/ROLLBACK_REPORT.md
publish:
depends_on: [post_rollback_verification]
steps:
- name: publish_rollback_artifacts
image: alpine:latest
commands:
- echo "📦 Rollback artifacts published"
- echo ""
- ls -lah ${LOGS_DIR}/rollback/
- echo ""
- du -sh ${LOGS_DIR}/rollback/
- name: notify_slack
image: alpine:latest
environment:
SLACK_WEBHOOK: ${SLACK_WEBHOOK_ALERTS}
commands:
- |
if [ -n "$SLACK_WEBHOOK" ]; then
apk add --no-cache curl jq
curl -X POST $SLACK_WEBHOOK \
-H 'Content-Type: application/json' \
-d '{
"text": "🔙 VAPORA Rollback Executed",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "🔙 **VAPORA Rollback Executed**\n\n*Rollback Details:*\n• Target: ${Rollback_Target:-kubernetes}\n• Environment: ${Rollback_Environment:-staging}\n• Deployment: ${Rollback_Deployment:-all}"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*⚠️ Action Required:*\n1. Verify service health\n2. Review application logs\n3. Investigate root cause\n4. Plan corrected deployment"
}
},
{
"type": "context",
"elements": [
{
"type": "mrkdwn",
"text": "*Reports*: Check rollback artifacts in logs\n*Commit*: '"${CI_COMMIT_SHA:0:8}"'\n*Branch*: '"${CI_COMMIT_BRANCH}"'"
}
]
}
]
}'
else
echo "⚠️ Slack webhook not configured"
fi