# VAPORA v1.0 Deployment Guide Complete guide for deploying VAPORA v1.0 to Kubernetes (self-hosted). **Version**: 0.1.0 **Status**: Production Ready **Last Updated**: 2025-11-10 --- ## Table of Contents 1. [Overview](#overview) 2. [Prerequisites](#prerequisites) 3. [Architecture](#architecture) 4. [Deployment Methods](#deployment-methods) 5. [Building Docker Images](#building-docker-images) 6. [Kubernetes Deployment](#kubernetes-deployment) 7. [Provisioning Deployment](#provisioning-deployment) 8. [Configuration](#configuration) 9. [Monitoring & Health Checks](#monitoring--health-checks) 10. [Scaling](#scaling) 11. [Troubleshooting](#troubleshooting) 12. [Rollback](#rollback) 13. [Security](#security) --- ## Overview VAPORA v1.0 is a **cloud-native multi-agent software development platform** that runs on Kubernetes. It consists of: - **6 Rust services**: Backend API, Frontend UI, Agents, MCP Server, LLM Router (embedded), Shared library - **2 Infrastructure services**: SurrealDB (database), NATS JetStream (messaging) - **Multi-IA routing**: Claude, OpenAI, Gemini, Ollama support - **12 specialized agents**: Architect, Developer, Reviewer, Tester, Documenter, etc. All services are containerized and deployed as Kubernetes workloads. --- ## Prerequisites ### Required Tools - **Kubernetes 1.25+** (K3s, RKE2, or managed Kubernetes) - **kubectl** (configured and connected to cluster) - **Docker** or **Podman** (for building images) - **Nushell** (for deployment scripts) ### Optional Tools - **Provisioning CLI** (for advanced deployment) - **Helm** (if using Helm charts) - **cert-manager** (for automatic TLS certificates) - **Prometheus/Grafana** (for monitoring) ### Cluster Requirements - **Minimum**: 4 CPU, 8GB RAM, 50GB storage - **Recommended**: 8 CPU, 16GB RAM, 100GB storage - **Production**: 16+ CPU, 32GB+ RAM, 200GB+ storage ### Storage - **Storage Class**: Required for SurrealDB PersistentVolumeClaim - **Options**: local-path, nfs-client, rook-ceph, or cloud provider storage - **Minimum**: 20Gi for database ### Ingress - **nginx-ingress** controller installed - **Domain name** pointing to cluster ingress IP - **TLS certificate** (optional, recommended for production) --- ## Architecture ``` ┌─────────────────────────────────────────────────────┐ │ Internet / Users │ └───────────────────────┬─────────────────────────────┘ │ ┌───────────────────────▼─────────────────────────────┐ │ Ingress (nginx) │ │ - vapora.example.com │ │ - TLS termination │ └────┬────────┬─────────┬─────────┬──────────────────┘ │ │ │ │ │ │ │ │ ┌────▼────┐ ┌▼─────┐ ┌▼─────┐ ┌▼──────────┐ │Frontend │ │Backend│ │ MCP │ │ │ │(Leptos) │ │(Axum) │ │Server│ │ │ │ 2 pods │ │2 pods │ │1 pod │ │ │ └─────────┘ └───┬───┘ └──────┘ │ │ │ │ │ ┌──────┴──────┬──────────┤ │ │ │ │ │ ┌────▼────┐ ┌───▼─────┐ ┌▼───────┐ │ │SurrealDB│ │ NATS │ │ Agents │ │ │StatefulS│ │JetStream│ │ 3 pods │ │ │ 1 pod │ │ 1 pod │ └────────┘ │ └─────────┘ └─────────┘ │ │ │ ┌────▼────────────────────────────────┐ │ │ Persistent Volume (20Gi) │ │ │ - SurrealDB data │ │ └─────────────────────────────────────┘ │ │ ┌─────────────────────────────────────────────▼──┐ │ External LLM APIs │ │ - Anthropic Claude API │ │ - OpenAI API │ │ - Google Gemini API │ │ - (Optional) Ollama local │ └───────────────────────────────────────────────┘ ``` --- ## Deployment Methods VAPORA supports two deployment methods: ### Method 1: Vanilla Kubernetes (Recommended for Getting Started) **Pros**: - Simple, well-documented - Standard K8s manifests - Easy to understand and modify - No additional tools required **Cons**: - Manual cluster management - Manual service ordering - No built-in rollback **Use when**: Learning, testing, or simple deployments ### Method 2: Provisioning (Recommended for Production) **Pros**: - Automated cluster creation - Declarative workflows - Built-in rollback - Service mesh integration - Secret management **Cons**: - Requires Provisioning CLI - More complex configuration - Steeper learning curve **Use when**: Production deployments, complex environments --- ## Building Docker Images ### Option 1: Using Nushell Script (Recommended) ```bash # Build all images (local registry) nu scripts/build-docker.nu # Build and push to Docker Hub nu scripts/build-docker.nu --registry docker.io --push # Build with specific tag nu scripts/build-docker.nu --tag v0.1.0 # Build without cache nu scripts/build-docker.nu --no-cache ``` ### Option 2: Manual Docker Build ```bash # From project root # Backend docker build -f crates/vapora-backend/Dockerfile -t vapora/backend:latest . # Frontend docker build -f crates/vapora-frontend/Dockerfile -t vapora/frontend:latest . # Agents docker build -f crates/vapora-agents/Dockerfile -t vapora/agents:latest . # MCP Server docker build -f crates/vapora-mcp-server/Dockerfile -t vapora/mcp-server:latest . ``` ### Image Sizes (Approximate) - **vapora/backend**: ~50MB (Alpine + Rust binary) - **vapora/frontend**: ~30MB (nginx + WASM) - **vapora/agents**: ~50MB (Alpine + Rust binary) - **vapora/mcp-server**: ~45MB (Alpine + Rust binary) --- ## Kubernetes Deployment ### Step 1: Configure Secrets Edit `kubernetes/03-secrets.yaml`: ```yaml stringData: # Generate strong JWT secret jwt-secret: "$(openssl rand -base64 32)" # Add your LLM API keys anthropic-api-key: "sk-ant-xxxxx" openai-api-key: "sk-xxxxx" gemini-api-key: "xxxxx" # Optional # Database credentials surrealdb-user: "root" surrealdb-pass: "$(openssl rand -base64 32)" ``` **IMPORTANT**: Never commit real secrets to version control! ### Step 2: Configure Ingress Edit `kubernetes/08-ingress.yaml`: ```yaml spec: rules: - host: vapora.yourdomain.com # Change this! ``` ### Step 3: Deploy Using Script (Recommended) ```bash # Dry run to validate nu scripts/deploy-k8s.nu --dry-run # Deploy to default namespace (vapora) nu scripts/deploy-k8s.nu # Deploy to custom namespace nu scripts/deploy-k8s.nu --namespace my-vapora # Skip secrets (if already created) nu scripts/deploy-k8s.nu --skip-secrets ``` ### Step 4: Manual Deploy (Alternative) ```bash # Apply manifests in order kubectl apply -f kubernetes/00-namespace.yaml kubectl apply -f kubernetes/01-surrealdb.yaml kubectl apply -f kubernetes/02-nats.yaml kubectl apply -f kubernetes/03-secrets.yaml kubectl apply -f kubernetes/04-backend.yaml kubectl apply -f kubernetes/05-frontend.yaml kubectl apply -f kubernetes/06-agents.yaml kubectl apply -f kubernetes/07-mcp-server.yaml kubectl apply -f kubernetes/08-ingress.yaml # Wait for rollout kubectl rollout status deployment/vapora-backend -n vapora kubectl rollout status deployment/vapora-frontend -n vapora ``` ### Step 5: Verify Deployment ```bash # Check all pods are running kubectl get pods -n vapora # Expected output: # NAME READY STATUS RESTARTS # surrealdb-0 1/1 Running 0 # nats-xxx 1/1 Running 0 # vapora-backend-xxx 1/1 Running 0 # vapora-backend-yyy 1/1 Running 0 # vapora-frontend-xxx 1/1 Running 0 # vapora-frontend-yyy 1/1 Running 0 # vapora-agents-xxx 1/1 Running 0 # vapora-agents-yyy 1/1 Running 0 # vapora-agents-zzz 1/1 Running 0 # vapora-mcp-server-xxx 1/1 Running 0 # Check services kubectl get svc -n vapora # Check ingress kubectl get ingress -n vapora ``` ### Step 6: Access VAPORA ```bash # Get ingress IP/hostname kubectl get ingress vapora -n vapora # Configure DNS # Point vapora.yourdomain.com to ingress IP # Access UI open https://vapora.yourdomain.com ``` --- ## Provisioning Deployment ### Step 1: Validate Configuration ```bash # Validate Provisioning workspace nu scripts/validate-provisioning.nu ``` ### Step 2: Create Cluster ```bash cd provisioning/vapora-wrksp # Validate configuration provisioning validate --all # Create cluster provisioning cluster create --config workspace.toml ``` ### Step 3: Deploy Services ```bash # Deploy infrastructure (database, messaging) provisioning workflow run workflows/deploy-infra.yaml # Deploy services (backend, frontend, agents) provisioning workflow run workflows/deploy-services.yaml # Or deploy full stack at once provisioning workflow run workflows/deploy-full-stack.yaml ``` ### Step 4: Health Check ```bash provisioning workflow run workflows/health-check.yaml ``` See `provisioning-integration/README.md` for details. --- ## Configuration ### Environment Variables #### Backend (`vapora-backend`) ```bash RUST_LOG=info,vapora=debug SURREALDB_URL=http://surrealdb:8000 SURREALDB_USER=root SURREALDB_PASS= NATS_URL=nats://nats:4222 JWT_SECRET= BIND_ADDR=0.0.0.0:8080 ``` #### Agents (`vapora-agents`) ```bash RUST_LOG=info,vapora_agents=debug NATS_URL=nats://nats:4222 BIND_ADDR=0.0.0.0:9000 ANTHROPIC_API_KEY= OPENAI_API_KEY= GEMINI_API_KEY= VAPORA_AGENT_CONFIG=/etc/vapora/agents.toml # Optional ``` #### MCP Server (`vapora-mcp-server`) ```bash RUST_LOG=info,vapora_mcp_server=debug # Port configured via --port flag ``` ### ConfigMaps Create custom configuration: ```bash kubectl create configmap agent-config -n vapora \ --from-file=agents.toml ``` Mount in deployment: ```yaml volumeMounts: - name: config mountPath: /etc/vapora volumes: - name: config configMap: name: agent-config ``` --- ## Monitoring & Health Checks ### Health Endpoints All services expose health check endpoints: - **Backend**: `GET /health` - **Frontend**: `GET /health.html` - **Agents**: `GET /health`, `GET /ready` - **MCP Server**: `GET /health` - **SurrealDB**: `GET /health` - **NATS**: `GET /healthz` (port 8222) ### Manual Health Checks ```bash # Backend health kubectl exec -n vapora deploy/vapora-backend -- \ curl -s http://localhost:8080/health # Database health kubectl exec -n vapora deploy/vapora-backend -- \ curl -s http://surrealdb:8000/health # NATS health kubectl exec -n vapora deploy/vapora-backend -- \ curl -s http://nats:8222/healthz ``` ### Kubernetes Probes All deployments have: - **Liveness Probe**: Restarts unhealthy pods - **Readiness Probe**: Removes pod from service until ready ### Logs ```bash # View backend logs kubectl logs -n vapora -l app=vapora-backend -f # View agent logs kubectl logs -n vapora -l app=vapora-agents -f # View all logs kubectl logs -n vapora -l app --all-containers=true -f ``` ### Metrics (Optional) Deploy Prometheus + Grafana: ```bash # Install Prometheus Operator helm install prometheus prometheus-community/kube-prometheus-stack \ -n monitoring --create-namespace # Access Grafana kubectl port-forward -n monitoring svc/prometheus-grafana 3000:80 ``` VAPORA services expose metrics on `/metrics` endpoint (future enhancement). --- ## Scaling ### Manual Scaling ```bash # Scale backend kubectl scale deployment vapora-backend -n vapora --replicas=4 # Scale frontend kubectl scale deployment vapora-frontend -n vapora --replicas=3 # Scale agents (for higher workload) kubectl scale deployment vapora-agents -n vapora --replicas=10 ``` ### Horizontal Pod Autoscaler (HPA) ```yaml apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: vapora-backend-hpa namespace: vapora spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: vapora-backend minReplicas: 2 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 70 ``` Apply: ```bash kubectl apply -f hpa.yaml ``` ### Resource Limits Adjust in deployment YAML: ```yaml resources: requests: cpu: 200m memory: 256Mi limits: cpu: 1000m memory: 1Gi ``` --- ## Troubleshooting ### Pods Not Starting ```bash # Check pod status kubectl get pods -n vapora # Describe pod for events kubectl describe pod -n vapora # Check logs kubectl logs -n vapora # Check previous logs (if crashed) kubectl logs -n vapora --previous ``` ### Database Connection Issues ```bash # Check SurrealDB is running kubectl get pod -n vapora -l app=surrealdb # Test connection from backend kubectl exec -n vapora deploy/vapora-backend -- \ curl -v http://surrealdb:8000/health # Check SurrealDB logs kubectl logs -n vapora surrealdb-0 ``` ### NATS Connection Issues ```bash # Check NATS is running kubectl get pod -n vapora -l app=nats # Test connection kubectl exec -n vapora deploy/vapora-backend -- \ curl http://nats:8222/varz # Check NATS logs kubectl logs -n vapora -l app=nats ``` ### Image Pull Errors ```bash # Check image pull secrets kubectl get secrets -n vapora # Create Docker registry secret kubectl create secret docker-registry regcred \ -n vapora \ --docker-server= \ --docker-username= \ --docker-password= # Add to deployment spec: imagePullSecrets: - name: regcred ``` ### Ingress Not Working ```bash # Check ingress controller is installed kubectl get pods -n ingress-nginx # Check ingress resource kubectl describe ingress vapora -n vapora # Check ingress logs kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx ``` --- ## Rollback ### Kubernetes Rollback ```bash # View rollout history kubectl rollout history deployment/vapora-backend -n vapora # Rollback to previous version kubectl rollout undo deployment/vapora-backend -n vapora # Rollback to specific revision kubectl rollout undo deployment/vapora-backend -n vapora --to-revision=2 ``` ### Provisioning Rollback ```bash cd provisioning/vapora-wrksp # List versions provisioning version list # Rollback to previous version provisioning rollback --to-version ``` --- ## Security ### Secrets Management - **Kubernetes Secrets**: Encrypted at rest (if configured in K8s) - **External Secrets Operator**: Sync from Vault, AWS Secrets Manager, etc. - **RustyVault**: Integrated with Provisioning ### Network Policies Apply network policies to restrict pod-to-pod communication: ```yaml apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: vapora-backend namespace: vapora spec: podSelector: matchLabels: app: vapora-backend ingress: - from: - podSelector: matchLabels: app: vapora-frontend ports: - protocol: TCP port: 8080 ``` ### TLS Certificates Use cert-manager for automatic TLS: ```bash # Install cert-manager kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.12.0/cert-manager.yaml # Create ClusterIssuer kubectl apply -f - < \ --ns vapora --db main backup.surql # Copy backup locally kubectl cp vapora/surrealdb-0:/backup.surql ./backup-$(date +%Y%m%d).surql ``` ### SurrealDB Restore ```bash # Copy backup to pod kubectl cp ./backup.surql vapora/surrealdb-0:/restore.surql # Restore kubectl exec -n vapora surrealdb-0 -- \ surreal import --conn http://localhost:8000 \ --user root --pass \ --ns vapora --db main /restore.surql ``` ### PVC Backup ```bash # Snapshot PVC (if supported by storage class) kubectl apply -f - <.nu --help` - **Kubernetes Docs**: https://kubernetes.io/docs/ --- **VAPORA v1.0** - Cloud-Native Multi-Agent Platform **Status**: Production Ready ✅