Vapora/provisioning/.github/workflows/deploy-kubernetes.yml
Jesús Pérez a395bd972f
Some checks failed
Rust CI / Security Audit (push) Has been cancelled
Rust CI / Check + Test + Lint (nightly) (push) Has been cancelled
Rust CI / Check + Test + Lint (stable) (push) Has been cancelled
mdBook Build & Deploy / Build mdBook (push) Has been cancelled
Nickel Type Check / Nickel Type Checking (push) Has been cancelled
mdBook Build & Deploy / Documentation Quality Check (push) Has been cancelled
mdBook Build & Deploy / Deploy to GitHub Pages (push) Has been cancelled
mdBook Build & Deploy / Notification (push) Has been cancelled
chore: add cd/ci ops
2026-01-12 03:36:55 +00:00

327 lines
11 KiB
YAML

name: Deploy to Kubernetes
on:
workflow_dispatch:
inputs:
mode:
description: 'Deployment mode'
required: true
default: 'multiuser'
type: choice
options:
- solo
- multiuser
- enterprise
dry_run:
description: 'Perform dry-run (no actual deployment)'
required: false
default: 'true'
type: choice
options:
- 'true'
- 'false'
environment:
description: 'Target environment'
required: true
type: choice
options:
- staging
- production
rollout_timeout:
description: 'Rollout timeout in seconds'
required: false
default: '300'
type: string
concurrency:
group: k8s-deployment-${{ github.ref }}-${{ inputs.environment }}
cancel-in-progress: false
jobs:
deploy-kubernetes:
name: Deploy ${{ inputs.mode || 'multiuser' }} to K8s
runs-on: ubuntu-latest
environment: ${{ inputs.environment || 'staging' }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: deployment-artifacts
path: artifacts/
- name: Install Nushell
run: |
cargo install nu --locked
nu --version
- name: Install kubectl
uses: azure/setup-kubectl@v3
with:
version: 'latest'
- name: Configure kubeconfig
run: |
mkdir -p ~/.kube
echo "${{ secrets.KUBE_CONFIG_STAGING }}" | base64 -d > ~/.kube/config
chmod 600 ~/.kube/config
kubectl cluster-info
if: ${{ inputs.environment == 'staging' }}
- name: Configure kubeconfig (production)
run: |
mkdir -p ~/.kube
echo "${{ secrets.KUBE_CONFIG_PRODUCTION }}" | base64 -d > ~/.kube/config
chmod 600 ~/.kube/config
kubectl cluster-info
if: ${{ inputs.environment == 'production' }}
- name: Create VAPORA namespace
run: |
kubectl create namespace vapora --dry-run=client -o yaml | kubectl apply -f -
kubectl label namespace vapora environment=${{ inputs.environment }} --overwrite
- name: Create deployment directory
run: |
mkdir -p deploy/kubernetes
cp artifacts/configmap.yaml deploy/kubernetes/
cp artifacts/deployment.yaml deploy/kubernetes/
cp artifacts/vapora-${{ inputs.mode || 'multiuser' }}.yaml deploy/kubernetes/config.yaml
- name: Validate Kubernetes manifests
run: |
kubectl apply --dry-run=client -f deploy/kubernetes/configmap.yaml
kubectl apply --dry-run=client -f deploy/kubernetes/deployment.yaml
echo "✓ Kubernetes manifests validated"
- name: Show deployment diff (dry-run)
if: ${{ inputs.dry_run == 'true' }}
run: |
echo "🔍 Deployment diff (dry-run):"
kubectl apply --dry-run=server -f deploy/kubernetes/configmap.yaml -o yaml
kubectl apply --dry-run=server -f deploy/kubernetes/deployment.yaml -o yaml
- name: Deploy ConfigMap
if: ${{ inputs.dry_run == 'false' }}
run: |
echo "📋 Deploying ConfigMap..."
kubectl apply -f deploy/kubernetes/configmap.yaml
sleep 5
kubectl get configmap -n vapora
- name: Deploy Deployments
if: ${{ inputs.dry_run == 'false' }}
run: |
echo "🚀 Deploying services..."
kubectl apply -f deploy/kubernetes/deployment.yaml
kubectl get deployments -n vapora
- name: Wait for rollout (backend)
if: ${{ inputs.dry_run == 'false' }}
run: |
echo "⏳ Waiting for backend deployment..."
kubectl rollout status deployment/vapora-backend -n vapora --timeout=${{ inputs.rollout_timeout }}s
- name: Wait for rollout (agents)
if: ${{ inputs.dry_run == 'false' }}
run: |
echo "⏳ Waiting for agents deployment..."
kubectl rollout status deployment/vapora-agents -n vapora --timeout=${{ inputs.rollout_timeout }}s
- name: Wait for rollout (llm-router)
if: ${{ inputs.dry_run == 'false' }}
run: |
echo "⏳ Waiting for llm-router deployment..."
kubectl rollout status deployment/vapora-llm-router -n vapora --timeout=${{ inputs.rollout_timeout }}s
- name: Verify pod health
if: ${{ inputs.dry_run == 'false' }}
run: |
echo "🏥 Checking pod health..."
kubectl get pods -n vapora
echo ""
echo "Pod details:"
kubectl describe pods -n vapora | grep -A 5 "Status:"
- name: Check deployment status
if: always()
run: |
echo "📊 Deployment Status:"
kubectl get deployments -n vapora -o wide
echo ""
echo "📋 Services:"
kubectl get services -n vapora
echo ""
echo "🔧 ConfigMaps:"
kubectl get configmaps -n vapora
- name: Get service endpoints
if: ${{ inputs.dry_run == 'false' }}
run: |
echo "🌐 Service Endpoints:"
kubectl get services -n vapora -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.clusterIP}{"\n"}{end}'
- name: Save deployment manifest
if: success()
run: |
cat > deploy/kubernetes/DEPLOYMENT.md << 'EOF'
# Kubernetes Deployment Details
**Deployment Time**: $(date -u +'%Y-%m-%dT%H:%M:%SZ')
**Mode**: ${{ inputs.mode || 'multiuser' }}
**Environment**: ${{ inputs.environment || 'staging' }}
**Namespace**: vapora
**Commit**: ${{ github.sha }}
**Workflow Run**: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
## Deployment Status
### Deployments
- **vapora-backend** - REST API server
- **vapora-agents** - Agent orchestration
- **vapora-llm-router** - LLM provider routing
### Configuration
- **ConfigMap**: vapora-config (environment data)
- **Namespace**: vapora (isolated environment)
## Kubernetes Commands
### View logs
```bash
# Backend logs
kubectl logs -f deployment/vapora-backend -n vapora
# Agents logs
kubectl logs -f deployment/vapora-agents -n vapora
# All pod logs
kubectl logs -f -l app=vapora -n vapora
```
### Check deployment status
```bash
kubectl get deployments -n vapora
kubectl get pods -n vapora
kubectl describe deployment vapora-backend -n vapora
```
### Rollback if needed
```bash
kubectl rollout undo deployment/vapora-backend -n vapora
kubectl rollout history deployment/vapora-backend -n vapora
```
### Port forwarding
```bash
kubectl port-forward -n vapora svc/vapora-backend 8001:8001
kubectl port-forward -n vapora svc/vapora-frontend 3000:3000
```
### Scale deployment
```bash
kubectl scale deployment vapora-backend --replicas=3 -n vapora
```
## Access Services
### Internal (ClusterIP)
- **Backend**: http://vapora-backend.vapora.svc.cluster.local:8001
- **Agents**: http://vapora-agents.vapora.svc.cluster.local:8002
- **LLM Router**: http://vapora-llm-router.vapora.svc.cluster.local:8003
- **Frontend**: http://vapora-frontend.vapora.svc.cluster.local:3000
### External (requires Ingress/LoadBalancer)
- Configure Ingress or LoadBalancer service
- See production documentation for external access setup
EOF
cat deploy/kubernetes/DEPLOYMENT.md
- name: Upload deployment manifests
if: always()
uses: actions/upload-artifact@v4
with:
name: k8s-deployment-${{ inputs.environment }}-${{ github.run_id }}
path: deploy/kubernetes/
retention-days: 30
- name: Create deployment annotation
if: ${{ inputs.dry_run == 'false' && success() }}
run: |
kubectl annotate deployment vapora-backend \
-n vapora \
deployment.kubernetes.io/revision=$(date +%s) \
github.deployment.run=${{ github.run_id }} \
github.deployment.commit=${{ github.sha }} \
--overwrite
- name: Post deployment summary
if: always()
uses: actions/github-script@v7
with:
script: |
const mode = '${{ inputs.mode || "multiuser" }}';
const env = '${{ inputs.environment || "staging" }}';
const isDryRun = '${{ inputs.dry_run }}' === 'true';
let message = `${isDryRun ? '🔍' : '✅'} **Kubernetes deployment ${isDryRun ? 'validated' : 'successful'}!**\n\n`;
message += `**Mode**: ${mode}\n`;
message += `**Environment**: ${env}\n`;
message += `**Dry-run**: ${isDryRun ? 'Yes' : 'No'}\n`;
message += `**Namespace**: vapora\n\n`;
message += `**Deployments**:\n`;
message += `- vapora-backend\n`;
message += `- vapora-agents\n`;
message += `- vapora-llm-router\n\n`;
message += `**Useful Commands**:\n`;
message += `\`\`\`bash\n`;
message += `# View deployment status\n`;
message += `kubectl get deployments -n vapora\n\n`;
message += `# View logs\n`;
message += `kubectl logs -f deployment/vapora-backend -n vapora\n\n`;
message += `# Port forward\n`;
message += `kubectl port-forward -n vapora svc/vapora-backend 8001:8001\n`;
message += `\`\`\`\n`;
// Only post to PR if it's a PR event
if (context.eventName === 'pull_request' || context.payload.pull_request) {
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: message
});
}
- name: Notify Slack on success
if: success()
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
text: |
VAPORA Kubernetes deployment successful!
Mode: ${{ inputs.mode || 'multiuser' }}
Environment: ${{ inputs.environment || 'staging' }}
Namespace: vapora
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
fields: repo,message,commit,author
continue-on-error: true
- name: Notify Slack on failure
if: failure()
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
text: |
VAPORA Kubernetes deployment failed!
Mode: ${{ inputs.mode || 'multiuser' }}
Environment: ${{ inputs.environment || 'staging' }}
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
fields: repo,message,commit,author
continue-on-error: true