> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kaireonai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Kubernetes (Helm)

> Deploy KaireonAI to any Kubernetes cluster using the provided Helm chart — an Enterprise on-prem deployment under a commercial license.

<Note>
  Running KaireonAI on your own Kubernetes cluster is an **Enterprise on-prem deployment under a commercial license**. The Helm chart and container images are provisioned as part of an Enterprise agreement — this is not a free or open download. [Contact sales](mailto:sales@kaireonai.com). See [Deployment options](/self-host/deploy/options).
</Note>

KaireonAI includes a production-ready Helm chart for deploying to any Kubernetes cluster. This gives you full control over scaling, networking, monitoring, and security.

## Prerequisites

* Kubernetes cluster (1.24+)
* Helm 3.x installed
* `kubectl` configured for your cluster
* PostgreSQL database (self-managed, RDS, or CloudNativePG)
* Redis (self-managed, ElastiCache, or included via Helm)

## What's Included

The Helm chart in `helm/` provides:

| Resource                 | Description                                                                                        |
| ------------------------ | -------------------------------------------------------------------------------------------------- |
| **API Deployment**       | Main Next.js application with health checks and HPA                                                |
| **Worker Deployment**    | Background job processor for pipelines and model retraining                                        |
| **ML Worker Deployment** | Python/FastAPI service for scikit-learn analysis (optional)                                        |
| **ConfigMaps**           | Application configuration (non-sensitive)                                                          |
| **Secrets**              | Database URLs, API keys, encryption keys                                                           |
| **Ingress**              | HTTPS ingress with TLS termination (ALB or nginx)                                                  |
| **HPA**                  | Horizontal Pod Autoscaler for API pods                                                             |
| **PodDisruptionBudget**  | Ensures availability during node maintenance                                                       |
| **NetworkPolicies**      | Restrict pod-to-pod and egress traffic                                                             |
| **Prometheus + Grafana** | Self-contained monitoring stack (Prometheus scrape config + 6 auto-provisioned Grafana dashboards) |

## Quick Install

```bash theme={null}
# Create namespace and secrets
kubectl create namespace kaireon

kubectl create secret generic kaireon-secrets \
  --namespace kaireon \
  --from-literal=DATABASE_URL='postgresql://user:pass@postgres:5432/kaireon' \
  --from-literal=REDIS_URL='redis://redis:6379' \
  --from-literal=NEXTAUTH_SECRET='your-secure-secret' \
  --from-literal=JWT_SIGNING_SECRET='your-jwt-secret-min-32-chars' \
  --from-literal=CONNECTOR_ENCRYPTION_KEY='your-32-byte-hex-key' \
  --from-literal=WEBHOOK_SIGNING_SECRET='your-webhook-secret' \
  --from-literal=API_KEY_PEPPER='your-api-key-pepper'

# Install the chart
helm install kaireon ./helm \
  --namespace kaireon \
  --set secrets.provider=external \
  --set api.image.repository=<YOUR_ACCOUNT_ID>.dkr.ecr.<REGION>.amazonaws.com/kaireon/api \
  --set api.image.tag=082a1e2 \
  --set ingress.host=kaireon.example.com
```

<Note>
  The command above pre-creates the `kaireon-secrets` Secret yourself, so set `secrets.provider` to any value other than `kubernetes` (e.g. `external`) — that tells the chart to use your Secret instead of templating a conflicting one of the same name. The chart's built-in `secrets.*` block only covers `NEXTAUTH_SECRET`, `JWT_SIGNING_SECRET`, and `CONNECTOR_ENCRYPTION_KEY`; creating the Secret yourself is how you also supply `WEBHOOK_SIGNING_SECRET` and `API_KEY_PEPPER`, which are required when `NODE_ENV=production`. If you keep the default Grafana stack, add a `GF_ADMIN_PASSWORD` entry to the Secret (or pass `--set monitoring.grafana.adminPassword=...`).
</Note>

### With ML Worker

To include the ML Worker for AI-powered segmentation, policy analysis, and content intelligence:

```bash theme={null}
helm install kaireon ./helm \
  --namespace kaireon \
  --set secrets.provider=external \
  --set api.image.repository=<YOUR_ACCOUNT_ID>.dkr.ecr.<REGION>.amazonaws.com/kaireon/api \
  --set api.image.tag=082a1e2 \
  --set mlWorker.enabled=true \
  --set mlWorker.image.repository=<YOUR_ACCOUNT_ID>.dkr.ecr.<REGION>.amazonaws.com/kaireon-ml \
  --set mlWorker.image.tag=latest \
  --set ingress.host=kaireon.example.com
```

When `mlWorker.enabled=true`, the chart automatically injects `ML_WORKER_URL` into the API pods — no manual configuration needed.

## Configuration

Key Helm values you can customize:

```yaml theme={null}
# values.yaml overrides
api:
  replicas: 3
  resources:
    requests:
      cpu: 500m
      memory: 512Mi
    limits:
      cpu: 2000m
      memory: 2Gi
  hpa:
    enabled: true
    minReplicas: 3
    maxReplicas: 20
    targetCPUUtilization: 70

worker:
  replicas: 2
  resources:
    requests:
      cpu: 1000m
      memory: 1Gi
    limits:
      cpu: 4000m
      memory: 4Gi

mlWorker:
  enabled: true
  replicas: 1
  resources:
    requests:
      cpu: 500m
      memory: 1Gi
    limits:
      cpu: 2000m
      memory: 4Gi

ingress:
  enabled: true
  className: alb
  host: app.kaireon.com
  aws:
    certificateArn: arn:aws:acm:us-east-1:...:certificate/...
    scheme: internet-facing

monitoring:
  prometheus:
    enabled: true
  grafana:
    enabled: true
```

Use `--set` to override any value:

```bash theme={null}
helm install kaireon ./helm \
  --namespace kaireon \
  --set api.replicas=3 \
  --set mlWorker.enabled=true \
  --set monitoring.prometheus.enabled=true
```

## Architecture

```mermaid theme={null}
graph TD
    ING["Ingress<br/>(ALB / nginx)"] --> API["API (Next.js)<br/>Port 3000"]
    API --> ML["ML Worker<br/>(FastAPI) 8000"]
    API --> WORK["Worker<br/>(BullMQ)"]

    API --> DB[("PostgreSQL<br/>(via PgBouncer)")]
    WORK --> DB
    ML --> DB
    API --> REDIS[("Redis")]
    WORK --> REDIS

    style ING fill:#065f46,stroke:#10b981,color:#d1fae5
    style API fill:#1e1b4b,stroke:#6366f1,color:#e0e7ff
    style ML fill:#312e81,stroke:#818cf8,color:#c7d2fe
    style WORK fill:#312e81,stroke:#818cf8,color:#c7d2fe
    style DB fill:#1e3a5f,stroke:#60a5fa,color:#bfdbfe
    style REDIS fill:#7c2d12,stroke:#f97316,color:#fed7aa
```

The API communicates with the ML Worker over an internal ClusterIP service (`kaireon-ml-worker:8000`). The ML Worker reads directly from PostgreSQL for schema data and analysis inputs.

## Monitoring Stack

When `monitoring.prometheus.enabled=true`, the chart deploys:

### Prometheus Metrics

KaireonAI exposes Prometheus metrics at `/api/metrics` (the bundled Prometheus scrape config targets this path; the endpoint requires an admin role or a valid API key):

| Metric                                  | Type      | Description                                |
| --------------------------------------- | --------- | ------------------------------------------ |
| `kaireon_decision_latency_ms`           | Histogram | Decision engine latency in milliseconds    |
| `kaireon_decision_delivery_total`       | Counter   | Total recommendation responses delivered   |
| `kaireon_pipeline_execution_latency_ms` | Histogram | Pipeline execution latency in milliseconds |
| `kaireon_http_request_duration_seconds` | Histogram | HTTP request duration in seconds           |
| `kaireon_dlq_depth`                     | Gauge     | Current dead-letter-queue depth            |

### Grafana Dashboards

Six pre-built dashboards are included in `helm/dashboards/`:

* **API Overview** — Request rates, latency percentiles, error rates
* **Decision Engine** — Pipeline stage durations, candidate counts, scoring latency, cache hit rates
* **Decision Performance** — Scoring model performance, qualification rates, conversion tracking, uplift metrics
* **Infrastructure** — CPU, memory, pod restarts, network throughput
* **Model Health** — Model AUC tracking, drift detection, retraining triggers
* **Worker Queues** — Queue depth, processing times, DLQ counts, failure rates

## Database Options

### Self-Managed PostgreSQL

Deploy PostgreSQL inside the cluster. The chart includes an internal PostgreSQL StatefulSet by default:

```yaml theme={null}
database:
  mode: internal
  internal:
    storage: 10Gi
```

Or use an operator like CloudNativePG:

```bash theme={null}
helm install pg-operator cloudnative-pg/cloudnative-pg --namespace cnpg-system --create-namespace
```

### Amazon RDS (External)

```yaml theme={null}
database:
  mode: external
  external:
    host: kaireon-db.cluster-abc.us-east-1.rds.amazonaws.com
    port: 5432
    name: kaireon
    username: admin
    existingSecret: kaireon-db-secret
    sslMode: require
```

## Upgrading

```bash theme={null}
# Update to a new image tag
helm upgrade kaireon ./helm \
  --namespace kaireon \
  --set api.image.tag=$(git rev-parse --short HEAD) \
  --set mlWorker.image.tag=$(git rev-parse --short HEAD)
```

## Rate Limiting & Circuit Breakers

* **Rate limiting** — KaireonAI protects API endpoints with a sliding-window rate limiter backed by Redis. You configure limits per endpoint via environment variables or platform settings.
* **Circuit breakers** — External integrations (connectors, webhooks) use circuit breaker patterns to prevent cascade failures. States cycle: closed → open → half-open.

## Troubleshooting

<AccordionGroup>
  <Accordion title="Secret creation errors ('already exists')">
    Kubernetes secrets are immutable by default once created. To update secrets, delete and recreate:

    ```bash theme={null}
    kubectl delete secret kaireon-secrets --namespace kaireon
    kubectl create secret generic kaireon-secrets \
      --namespace kaireon \
      --from-literal=DATABASE_URL='...' \
      --from-literal=REDIS_URL='...' \
      --from-literal=NEXTAUTH_SECRET='...' \
      --from-literal=JWT_SIGNING_SECRET='...' \
      --from-literal=CONNECTOR_ENCRYPTION_KEY='...' \
      --from-literal=WEBHOOK_SIGNING_SECRET='...' \
      --from-literal=API_KEY_PEPPER='...'
    ```

    Then restart the pods to pick up the new values:

    ```bash theme={null}
    kubectl rollout restart deployment kaireon-api --namespace kaireon
    ```
  </Accordion>

  <Accordion title="API pods OOMKilled or CrashLoopBackOff">
    The Next.js application requires at least 512Mi of memory. If pods are being OOMKilled, increase the memory limit:

    ```yaml theme={null}
    api:
      resources:
        limits:
          memory: 2Gi
    ```

    For the worker, allocate at least 1Gi. Check pod events for the specific reason:

    ```bash theme={null}
    kubectl describe pod -l app=kaireon-api --namespace kaireon
    ```
  </Accordion>

  <Accordion title="Health probe failures (readiness/liveness)">
    The API pods use a liveness probe at `/api/health` and a readiness probe at `/api/ready` (both on port 3000). If probes fail during startup, increase the `initialDelaySeconds`:

    ```yaml theme={null}
    api:
      readinessProbe:
        initialDelaySeconds: 30
        periodSeconds: 10
      livenessProbe:
        initialDelaySeconds: 45
        periodSeconds: 15
    ```

    Startup can take 15-30 seconds as the app validates environment variables and connects to PostgreSQL. Check pod logs if probes continue to fail:

    ```bash theme={null}
    kubectl logs -l app=kaireon-api --namespace kaireon --tail=50
    ```
  </Accordion>

  <Accordion title="ECR image pull errors ('ImagePullBackOff')">
    Ensure the node IAM role or service account has `ecr:GetAuthorizationToken` and `ecr:BatchGetImage` permissions. For EKS, verify that the OIDC provider is configured and the service account is annotated:

    ```bash theme={null}
    kubectl describe pod -l app=kaireon-api --namespace kaireon | grep -A5 Events
    ```
  </Accordion>

  <Accordion title="Cannot connect to PostgreSQL from pods">
    Verify the database is reachable from within the cluster. Common issues include missing VPC peering, security group rules, or incorrect hostnames. Test connectivity from a debug pod:

    ```bash theme={null}
    kubectl run pg-test --rm -it --image=postgres:16 --namespace kaireon -- \
      psql 'postgresql://user:pass@your-db-host:5432/kaireon' -c 'SELECT 1'
    ```
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="ML Worker" icon="microchip" href="/self-host/deploy/ml-worker">
    Configure the ML Worker for AI features.
  </Card>

  <Card title="Operations" icon="gauge" href="/self-host/architecture/operations">
    Configure Prometheus metrics and Grafana dashboards.
  </Card>

  <Card title="Scaling Guide" icon="arrows-maximize" href="/self-host/architecture/scaling">
    Scaling guidance for high-throughput deployments.
  </Card>

  <Card title="Cloud Deployment" icon="cloud" href="/self-host/deploy/cloud">
    One-click deployment to AWS App Runner.
  </Card>
</CardGroup>
