Overview
The chart packages everything needed for a production KaireonAI deployment:Prerequisites
- Kubernetes 1.24+
- Helm 3.x
kubectlconfigured for your cluster- Container images pushed to a registry accessible from the cluster
Quick Start
Add the chart
helm/:Install with minimal values
Verify the deployment
Deployment Modes
KaireonAI supports three deployment modes depending on your environment and requirements.Dev Mode — Single replicas, all in-cluster
Dev Mode — Single replicas, all in-cluster
t3.medium node (~2 vCPU, 4 GiB).values-minimal.yaml:- API and worker: 1 replica each
- HPA and KEDA disabled
- Prometheus and Grafana disabled
- Reduced resource requests (256Mi memory, 250m CPU)
- Smaller PVC sizes (5 GiB database, 2 GiB Redis)
App Mode — External database and Redis, production-ready
App Mode — External database and Redis, production-ready
Full Mode — All components including monitoring stack
Full Mode — All components including monitoring stack
values.yaml enables the full mode with 3 API replicas, 2 worker replicas, HPA, KEDA autoscaling, Prometheus, and Grafana.Values Reference
All configurable values are defined inhelm/values.yaml. The sections below document each configuration group.
Global
API
api.* — API deployment configuration
api.* — API deployment configuration
- Scale up: stabilization window of 60s, add up to 4 pods per 60s
- Scale down: stabilization window of 300s, remove up to 10% of pods per 60s
Worker
worker.* — Worker deployment configuration
worker.* — Worker deployment configuration
ML Worker
mlWorker.* — ML Worker deployment configuration (optional)
mlWorker.* — ML Worker deployment configuration (optional)
ML_WORKER_URL into the API pods.Config
config.* — Application configuration
config.* — Application configuration
config.CORS_ALLOWED_ORIGINS ships empty on purpose. With NODE_ENV=production (the default) the API’s startup env-validation refuses to boot unless it is set to an explicit, non-wildcard origin, so the chart fails at helm install / helm template time with an actionable message rather than letting the pod crash-loop. Supply your app’s public origin(s) at install:--set config.CORS_ALLOWED_ORIGINS=https://app.example.com\,https://admin.example.com (or set it in a -f values override, where commas need no escaping). scripts/deploy.sh reads a CORS_ALLOWED_ORIGINS env var and defaults to http://localhost:3000 for its dev-mode path.Database
database.* — PostgreSQL configuration
database.* — PostgreSQL configuration
database.mode to control how PostgreSQL is provisioned:internal— Deploys a PostgreSQL 16 StatefulSet inside the clusterexternal— Connects to a managed database (RDS, Cloud SQL, Supabase, etc.)
Secrets
secrets.* — Application secrets
secrets.* — Application secrets
secrets.provider: kubernetes the chart templates the kaireon-secrets Secret with the keys above plus the derived DATABASE_URL / REDIS_URL (and GF_ADMIN_PASSWORD when Grafana is enabled). Set secrets.provider: aws-secrets-manager to pull the same keys from an ExternalSecret instead.WEBHOOK_SIGNING_SECRET and API_KEY_PEPPER are both required when NODE_ENV=production — the API refuses to start without them. The chart now templates both keys (in secrets.yaml for the kubernetes provider and external-secret.yaml for aws-secrets-manager), and scripts/deploy.sh auto-generates them alongside the other secrets. Provide your own values via --set secrets.WEBHOOK_SIGNING_SECRET=… / --set secrets.API_KEY_PEPPER=…, a values override, or your external secrets manager.Redis
redis.* — Redis configuration
redis.* — Redis configuration
redis.mode to control how Redis is provisioned:internal— Deploys a Redis 7 StatefulSet inside the clusterexternal— Connects to a managed Redis (ElastiCache, Upstash, etc.)
PgBouncer
pgbouncer.* — Connection pooling configuration
pgbouncer.* — Connection pooling configuration
helm/values.yaml:209-225. PgBouncer fronts PostgreSQL so the API tier shares a small pool against the database while individual Next.js request handlers can each open their own client connection.transaction mode) is recommended for Next.js applications. It allows multiple clients to share database connections between transactions, significantly reducing the number of connections to PostgreSQL.Ingress
ingress.* — Ingress and TLS configuration
ingress.* — Ingress and TLS configuration
className: alb):className: nginx):DNS
externalDns.* — Route53 via external-dns
externalDns.* — Route53 via external-dns
helm/values.yaml:246-249. When enabled, the chart adds the annotations external-dns expects on the Ingress so Route53 records track the cluster automatically. The companion external-dns controller is not installed by this chart — operators run it once per cluster from the upstream Helm chart.Monitoring
monitoring.* — Prometheus and Grafana
monitoring.* — Prometheus and Grafana
Event Bus (Optional)
Setconfig.EVENT_PUBLISHER to activate an event bus backend. The default is redis which requires no extra configuration.
kafka.* / msk.* / eventbridge.* / kinesis.* — Event bus backends
kafka.* / msk.* / eventbridge.* / kinesis.* — Event bus backends
Interaction Store (Optional)
Setconfig.INTERACTION_STORE to activate an alternative interaction history backend. The default is pg (PostgreSQL).
dynamodb.* / keyspaces.* / scylla.* — Interaction store backends
dynamodb.* / keyspaces.* / scylla.* — Interaction store backends
Search Index (Optional)
Setconfig.SEARCH_INDEX to activate an alternative search backend. The default is pg (PostgreSQL tsvector).
opensearch.* — OpenSearch configuration
opensearch.* — OpenSearch configuration
Cron Tier
cron.* — scheduled CronJob triggers
cron.* — scheduled CronJob triggers
cron.enabled: true (the default) the chart creates one Kubernetes CronJob per entry in cron.schedules. Each job runs a small curlimages/curl container that fires a single authenticated POST — curl -H "Authorization: Bearer $CRON_SECRET" <baseUrl><path> — at the in-cluster API service; the actual work runs inside the API tier.CRON_SECRET (or CRON_TOKEN) is set — set cron.enabled: false to rely on those instead, or disable the in-process schedulers (MAINTENANCE_SCHEDULER_ENABLED=false, FLOW_INTERNAL_SCHEDULER_ENABLED=false) when you prefer the CronJobs. The API tier must have CRON_SECRET available for the jobs to authenticate.Outbox Publisher
outboxPublisher.* — dedicated outbox relay pod
outboxPublisher.* — dedicated outbox relay pod
outboxPublisher.enabled: true (the default) the chart deploys a dedicated pod that polls the outbox_events table and publishes each event through the configured EVENT_PUBLISHER. Splitting it from the main worker tier keeps outbox tail-latency independent of long-running batch jobs.Large-Topology Aliases
The following keys appear only in the large-enterprise overlay athelm/values-large.yaml. The base chart (helm/values.yaml) does not define them — they are layered in via helm upgrade -f helm/values.yaml -f helm/values-large.yaml. Each is a high-level alias that the chart maps onto the per-backend sections above. See values-large.yaml — enterprise topology for the full overlay.
postgresExternalReplicas.* — Read-replica advisory count
postgresExternalReplicas.* — Read-replica advisory count
helm/values-large.yaml:163. A single integer that records how many read replicas the operator has provisioned alongside the primary. Advisory only — the chart does not itself create RDS replicas; consumers (e.g. the read-only analytics path) read this number when deciding whether to fan out reads.postgresExternalReplicas is meaningful only when database.mode: external (or, in the large overlay, postgres.mode: external). For internal-StatefulSet deployments leave it unset.eventbus.* — Event-bus backend selector
eventbus.* — Event-bus backend selector
helm/values-large.yaml:173-175. A high-level alias that picks one of the per-backend blocks (kafka.*, msk.*, eventbridge.*, kinesis.*). The base chart instead drives this from config.EVENT_PUBLISHER (redis | kafka | msk | eventbridge | kinesis); the large overlay adds the alias for callers who prefer to read the choice as a single key. Either form is honoured — the operator should not set both unless the values agree.interactionStore.* — Interaction-store backend selector
interactionStore.* — Interaction-store backend selector
helm/values-large.yaml:177-178. The large-overlay alias for config.INTERACTION_STORE. Selects which write path receives the partitioned interaction-history rows. Each backend still requires its own per-backend block (dynamodb.*, scylla.*, keyspaces.*) to be filled in.Grafana Dashboards
The chart includes 6 pre-built Grafana dashboards that are auto-provisioned fromhelm/dashboards/. When monitoring.grafana.enabled=true, these dashboards are available immediately after deployment.
/api/metrics (the bundled Prometheus deployment is pre-configured to scrape this path on port 3000; the endpoint requires an admin role or a valid API key). Key metrics include kaireon_decision_latency_ms, kaireon_decision_delivery_total, kaireon_pipeline_execution_latency_ms, kaireon_http_request_duration_seconds, and kaireon_dlq_depth.