Vapora/provisioning/.woodpecker/deploy-kubernetes.yml

353 lines
12 KiB
YAML
Raw Normal View History

2026-01-12 03:36:55 +00:00
# VAPORA Woodpecker Pipeline - Deploy to Kubernetes
# Deploys VAPORA to Kubernetes cluster with dry-run and verification
# Triggers on: manual promotion
trigger:
event: [promote]
branch: [main, develop]
variables:
ARTIFACTS_DIR: provisioning/artifacts
LOGS_DIR: provisioning/logs
VAPORA_NAMESPACE: vapora
stages:
setup:
steps:
- name: prepare
image: alpine:latest
commands:
- mkdir -p ${ARTIFACTS_DIR} ${LOGS_DIR}
- echo "☸️ VAPORA Kubernetes Deployment Pipeline"
- echo "Commit: ${CI_COMMIT_SHA:0:8}"
- echo "Branch: ${CI_COMMIT_BRANCH}"
- echo "Event: ${CI_PIPELINE_EVENT}"
install_dependencies:
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
- jinja2 --version
- yq --version
configure_kubernetes:
depends_on: [install_dependencies]
steps:
- name: setup_kubeconfig_staging
image: alpine:latest
environment:
KUBE_CONFIG_STAGING: ${KUBE_CONFIG_STAGING}
commands:
- mkdir -p ~/.kube
- echo "$KUBE_CONFIG_STAGING" | base64 -d > ~/.kube/config
- chmod 600 ~/.kube/config
- echo "✓ Kubeconfig configured for staging"
when:
evaluate: 'return build.Deploy_Environment == "staging"'
- name: setup_kubeconfig_production
image: alpine:latest
environment:
KUBE_CONFIG_PRODUCTION: ${KUBE_CONFIG_PRODUCTION}
commands:
- mkdir -p ~/.kube
- echo "$KUBE_CONFIG_PRODUCTION" | base64 -d > ~/.kube/config
- chmod 600 ~/.kube/config
- echo "✓ Kubeconfig configured for production"
when:
evaluate: 'return build.Deploy_Environment == "production"'
- name: verify_cluster
image: alpine:latest
commands:
- apk add --no-cache curl
- kubectl cluster-info
- kubectl get nodes
- echo "✓ Kubernetes cluster accessible"
validate_manifests:
depends_on: [configure_kubernetes]
steps:
- name: validate_kubernetes_manifests
image: rust:latest
environment:
RUST_LOG: warn
commands:
- apt-get update && apt-get install -y curl jq yq
- cargo install nu --locked > /dev/null 2>&1
- cargo install nickel --locked > /dev/null 2>&1
- pip install jinja2-cli > /dev/null 2>&1
- |
echo "Validating Kubernetes manifests..."
if [ -f "${ARTIFACTS_DIR}/deployment.yaml" ]; then
yq eval '.' "${ARTIFACTS_DIR}/deployment.yaml" > /dev/null && echo "✓ Deployment manifest valid"
yq eval '.' "${ARTIFACTS_DIR}/configmap.yaml" > /dev/null && echo "✓ ConfigMap manifest valid"
else
echo "⚠️ Manifests not found, generating from Nickel"
cd provisioning
nu scripts/ci-pipeline.nu --artifact-dir ../${ARTIFACTS_DIR} --mode multiuser 2>&1 | tee ../${LOGS_DIR}/k8s-generation.log
fi
- name: dry_run_validation
image: alpine:latest
commands:
- apk add --no-cache curl
- |
echo "🔍 Performing dry-run validation..."
kubectl apply -f ${ARTIFACTS_DIR}/deployment.yaml --dry-run=server -n ${VAPORA_NAMESPACE} --record 2>&1 | tee ${LOGS_DIR}/dry-run-validation.log
if [ $? -eq 0 ]; then
echo "✓ Dry-run validation passed"
else
echo "❌ Dry-run validation failed"
exit 1
fi
create_namespace:
depends_on: [validate_manifests]
steps:
- name: ensure_namespace
image: alpine:latest
commands:
- apk add --no-cache curl
- |
echo "📁 Creating/verifying vapora namespace..."
kubectl get namespace ${VAPORA_NAMESPACE} > /dev/null 2>&1 || kubectl create namespace ${VAPORA_NAMESPACE}
echo "✓ Namespace ready"
- name: setup_rbac
image: alpine:latest
commands:
- apk add --no-cache curl
- |
echo "🔐 Setting up RBAC..."
# Default service account has basic access
kubectl get serviceaccount default -n ${VAPORA_NAMESPACE} > /dev/null 2>&1 || {
echo "Creating default service account"
kubectl create serviceaccount default -n ${VAPORA_NAMESPACE}
}
echo "✓ RBAC configured"
deploy_configmap:
depends_on: [create_namespace]
steps:
- name: apply_configmap
image: alpine:latest
commands:
- apk add --no-cache curl
- |
echo "⚙️ Applying ConfigMap..."
kubectl apply -f ${ARTIFACTS_DIR}/configmap.yaml -n ${VAPORA_NAMESPACE} --record
echo "✓ ConfigMap applied"
- name: verify_configmap
image: alpine:latest
commands:
- apk add --no-cache curl
- |
echo "✓ ConfigMap contents:"
kubectl get configmap -n ${VAPORA_NAMESPACE} -o yaml | head -50
deploy_services:
depends_on: [deploy_configmap]
steps:
- name: apply_deployments
image: alpine:latest
commands:
- apk add --no-cache curl
- |
echo "🚀 Applying Kubernetes Deployments..."
kubectl apply -f ${ARTIFACTS_DIR}/deployment.yaml -n ${VAPORA_NAMESPACE} --record
echo "✓ Deployments applied"
- name: monitor_rollout_backend
image: alpine:latest
commands:
- apk add --no-cache curl
- |
echo "⏳ Waiting for backend rollout..."
kubectl rollout status deployment/vapora-backend -n ${VAPORA_NAMESPACE} --timeout=5m
echo "✓ Backend deployment ready"
- name: monitor_rollout_agents
image: alpine:latest
commands:
- apk add --no-cache curl
- |
echo "⏳ Waiting for agents rollout..."
kubectl rollout status deployment/vapora-agents -n ${VAPORA_NAMESPACE} --timeout=5m
echo "✓ Agents deployment ready"
- name: monitor_rollout_llm_router
image: alpine:latest
commands:
- apk add --no-cache curl
- |
echo "⏳ Waiting for LLM router rollout..."
kubectl rollout status deployment/vapora-llm-router -n ${VAPORA_NAMESPACE} --timeout=5m
echo "✓ LLM router deployment ready"
verify_deployment:
depends_on: [deploy_services]
steps:
- name: check_pods
image: alpine:latest
commands:
- apk add --no-cache curl
- |
echo "🔍 Verifying pod status..."
kubectl get pods -n ${VAPORA_NAMESPACE} -o wide
echo ""
echo "Checking pod readiness..."
kubectl get pods -n ${VAPORA_NAMESPACE} -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.conditions[?(@.type=="Ready")].status}{"\n"}{end}'
- name: check_services
image: alpine:latest
commands:
- apk add --no-cache curl
- |
echo "🔍 Verifying services..."
kubectl get services -n ${VAPORA_NAMESPACE} -o wide
echo ""
echo "Service endpoints:"
kubectl get endpoints -n ${VAPORA_NAMESPACE}
- name: collect_logs
image: alpine:latest
commands:
- apk add --no-cache curl
- |
echo "📋 Collecting deployment logs..."
mkdir -p ${LOGS_DIR}/kubernetes
kubectl get events -n ${VAPORA_NAMESPACE} --sort-by='.lastTimestamp' > ${LOGS_DIR}/kubernetes/events.log 2>&1
kubectl logs -n ${VAPORA_NAMESPACE} deployment/vapora-backend --tail=100 > ${LOGS_DIR}/kubernetes/backend.log 2>&1
kubectl logs -n ${VAPORA_NAMESPACE} deployment/vapora-agents --tail=100 > ${LOGS_DIR}/kubernetes/agents.log 2>&1
kubectl logs -n ${VAPORA_NAMESPACE} deployment/vapora-llm-router --tail=100 > ${LOGS_DIR}/kubernetes/llm-router.log 2>&1
- name: annotate_deployment
image: alpine:latest
commands:
- apk add --no-cache curl
- |
echo "📝 Annotating deployments..."
kubectl annotate deployment vapora-backend -n ${VAPORA_NAMESPACE} \
deployment.vapora/timestamp="$(date -u +'%Y-%m-%dT%H:%M:%SZ')" \
deployment.vapora/commit="${CI_COMMIT_SHA:0:8}" \
deployment.vapora/branch="${CI_COMMIT_BRANCH}" \
--overwrite
generate_report:
depends_on: [verify_deployment]
steps:
- name: create_deployment_report
image: alpine:latest
commands:
- |
mkdir -p ${LOGS_DIR}
cat > ${LOGS_DIR}/KUBERNETES_DEPLOYMENT_REPORT.md << 'EOF'
# Kubernetes Deployment Report
**Deployment Time**: $(date -u +'%Y-%m-%dT%H:%M:%SZ')
**Commit**: ${CI_COMMIT_SHA}
**Branch**: ${CI_COMMIT_BRANCH}
**Namespace**: ${VAPORA_NAMESPACE}
## Status
✅ Kubernetes deployment successful
## Deployments
- **vapora-backend**: Running with configured replicas
- **vapora-agents**: Running with configured replicas
- **vapora-llm-router**: Running with configured replicas
## Verification Commands
```bash
# Check deployments
kubectl get deployments -n ${VAPORA_NAMESPACE}
# View pods
kubectl get pods -n ${VAPORA_NAMESPACE}
# Check logs
kubectl logs -f deployment/vapora-backend -n ${VAPORA_NAMESPACE}
# Port forward for local testing
kubectl port-forward -n ${VAPORA_NAMESPACE} svc/vapora-backend 8001:8001
# View events
kubectl get events -n ${VAPORA_NAMESPACE} --sort-by='.lastTimestamp'
# Check rollout status
kubectl rollout history deployment/vapora-backend -n ${VAPORA_NAMESPACE}
```
## Next Steps
1. Run health checks to verify all services
2. Monitor logs for any errors
3. Test API endpoints
4. Set up monitoring and alerts
5. Plan rollout to next environment
EOF
cat ${LOGS_DIR}/KUBERNETES_DEPLOYMENT_REPORT.md
publish:
depends_on: [generate_report]
steps:
- name: publish_results
image: alpine:latest
commands:
- echo "📦 Kubernetes deployment complete"
- echo ""
- echo "Logs:"
- ls -lah ${LOGS_DIR}/kubernetes/
- echo ""
- echo "Report:"
- cat ${LOGS_DIR}/KUBERNETES_DEPLOYMENT_REPORT.md
- 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 Kubernetes deployment successful!",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "✅ **VAPORA Kubernetes Deployment Successful**\n\n*Deployments Ready:*\n• backend (vapora-backend)\n• agents (vapora-agents)\n• llm-router (vapora-llm-router)"
}
},
{
"type": "context",
"elements": [
{
"type": "mrkdwn",
"text": "*Commit*: '"${CI_COMMIT_SHA:0:8}"'\n*Branch*: '"${CI_COMMIT_BRANCH}"'\n*Namespace*: '"${VAPORA_NAMESPACE}"'\n*Triggered By*: '"${CI_COMMIT_AUTHOR}"'"
}
]
}
]
}'
else
echo "⚠️ Slack webhook not configured"
fi