Deploy on Kubernetes with Helm
Install CodeVector on any Kubernetes cluster with the official Helm chart. Per-replica usage-buffer PVC, pre-upgrade migration hook, controller-agnostic Ingress, and a one-line helm repo install path.
Your gateway URL
Pin your own gateway hostname and we'll rewrite the routes and curl examples on every docs page so you can click straight through to the live console. Stored locally in your browser.
This guide installs CodeVector on Kubernetes with the official Helm chart. It is the equivalent of the Docker Compose quickstart for clusters. The chart deploys two things:
- A StatefulSet running the CodeVector app (nginx plus the Node server, supervised, listening on port 8080).
- A Helm pre-install / pre-upgrade Job that runs database migrations.
It does not install Postgres. Bring your own managed Postgres reachable from the cluster. The same recommendation applies to the Docker stack in production.
Prerequisites
- Kubernetes 1.30 or newer (tested on 1.31, 1.32, 1.33).
- Helm 4.x (Helm 3.12+ also works).
- A reachable PostgreSQL 18 instance (recommended; PG 16 and 17 also supported). TLS is strongly recommended; append
?sslmode=requiretoDATABASE_URL. - A default StorageClass that supports
ReadWriteOnce, or one named invalues.yaml. Each StatefulSet replica gets its own PVC for the degraded-mode usage buffer. - An Ingress controller (nginx, Traefik, AWS Load Balancer Controller, etc.) if you want the chart’s
Ingressresource. TLS termination is yours to wire up. - A license token issued by CodeVector. Request one via the button above.
1. Add the Helm repository
The chart is published as a static Helm repository on this site.
helm repo add codevector https://codevector.ai/helm
helm repo update
helm search repo codevector
You should see:
NAME CHART VERSION APP VERSION DESCRIPTION
codevector/codevector <version> <version> CodeVector AI gateway...
The two columns reflect the latest published chart and app versions; do not hardcode either into your install commands - let Helm resolve them.
Prefer a direct download? The tarball is also a static asset. Open https://codevector.ai/helm/ to see the current chart version (and a one-click download link), then fetch the matching tarball:
# Replace <version> with the chart version shown at codevector.ai/helm/
curl -fLO https://codevector.ai/helm/codevector-<version>.tgz
tar -tzf codevector-<version>.tgz | head
Either form can be passed to helm install.
2. Create the namespace
kubectl create namespace codevector
3. Create the image pull secret
The image is served by CodeVector’s license-aware registry proxy at
registry.codevector.ai. Create a docker-registry Secret in the namespace
using your license token as the password. The chart references it via
imagePullSecrets in your values file (step 5).
kubectl -n codevector create secret docker-registry codevector-pull \
--docker-server=registry.codevector.ai \
--docker-username=license \
--docker-password='<your-LICENSE_TOKEN>'
Username can be anything (license is the convention). The proxy verifies the
license signature on every pull and rejects revoked or expired tokens at the
registry layer, before the binary reaches your cluster. If your license is
revoked between deploys, new pulls fail immediately.
If you mirror the image to a private registry of your own, create the pull
Secret for that registry instead and override image.repository in your
values file.
4. Generate and store the application secrets
# Session secret: exactly 32 chars
SESSION_SECRET=$(openssl rand -hex 16)
# Key-encryption key (KEK): minimum 32 chars
KEK_PRIMARY=$(openssl rand -hex 32)
kubectl -n codevector create secret generic codevector-secrets \
--from-literal=DATABASE_URL='postgres://codevector:STRONG_PASSWORD@db.example.com:5432/codevector?sslmode=require' \
--from-literal=SESSION_SECRET="$SESSION_SECRET" \
--from-literal=KEK_PRIMARY="$KEK_PRIMARY" \
--from-literal=LICENSE_TOKEN='<your-license-token>'
The chart will read these via envFrom on both the app StatefulSet and the migration Job.
Optional keys (add --from-literal= for each one you need):
| Key | When to set |
|---|---|
KEK_SECONDARY | During KEK rotation (see Day-2 operations below). |
SMTP_PASSWORD | Only if you enable SMTP in config.smtp. |
5. Write a values file
Save the following as codevector-values.yaml and replace the host with yours.
The chart defaults to image.tag: latest; set it explicitly to pin a version
(strongly recommended for production). Look up the current app version on the
Helm repo page - do not copy the placeholder
below verbatim:
# Optional. Defaults to "latest". Pin in production.
# image:
# tag: "<app-version>" # app version shown at codevector.ai/helm/
imagePullSecrets:
- name: codevector-pull
secrets:
existingSecret: codevector-secrets
config:
gatewayPublicUrl: https://gateway.acme.com
ingress:
enabled: true
className: nginx
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
hosts:
- host: gateway.acme.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: codevector-tls
hosts:
- gateway.acme.com
persistence:
storageClass: gp3
size: 5Gi
If your Ingress controller is not nginx, set ingress.className accordingly (traefik, alb, etc.) and add any required annotations under ingress.annotations.
6. Install the chart
helm install codevector codevector/codevector \
--namespace codevector \
--values codevector-values.yaml
Helm runs the migration Job first (pre-install hook), waits for it to succeed, and only then rolls out the StatefulSet.
7. Verify
# Migration Job
kubectl -n codevector get jobs
kubectl -n codevector logs job/codevector-migrate
# App pods
kubectl -n codevector rollout status statefulset/codevector
kubectl -n codevector get pods
# Health (without an Ingress, or for a sanity check)
kubectl -n codevector port-forward svc/codevector 8080:8080
curl http://localhost:8080/health
8. Sign in
The bootstrap admin email and one-time password are printed to the app log on first start:
kubectl -n codevector logs statefulset/codevector | grep -i bootstrap
Sign in at https://gateway.acme.com/, change the password immediately, and configure providers from the admin console.
What the chart deploys
| Object | Name | Purpose |
|---|---|---|
StatefulSet | codevector | App pods (nginx + Node). One PVC per replica for the usage buffer. |
Service (ClusterIP) | codevector | Stable in-cluster endpoint on port 8080. |
Service (headless) | codevector-headless | Stable pod DNS for the StatefulSet. |
Ingress (optional) | codevector | HTTP routing to the Service. Controller-agnostic; off by default. |
ConfigMap | codevector-config | Non-sensitive runtime configuration. |
Secret (optional) | codevector-secrets | Only when secrets.existingSecret is empty. Prefer the out-of-band path. |
ServiceAccount | codevector | Token automounting disabled. |
Job (Helm hook) | codevector-migrate | Runs migrations on pre-install and pre-upgrade. |
PersistentVolumeClaim | usage-buffer-codevector-N | One per replica, mounted at /var/lib/codevector/usage-buffer. |
Chart layout
deploy/helm/codevector/
├── Chart.yaml
├── values.yaml
├── README.md
├── .helmignore
└── templates/
├── _helpers.tpl
├── NOTES.txt
├── configmap.yaml
├── ingress.yaml # rendered only when ingress.enabled=true
├── job-migrate.yaml # Helm hook: pre-install,pre-upgrade
├── secret.yaml # rendered only when secrets.existingSecret is empty
├── service.yaml # ClusterIP + headless service
├── serviceaccount.yaml
└── statefulset.yaml
To inspect any of these locally before installing, look up the current chart version on the Helm repo page and unpack the matching tarball:
# Replace <version> with the chart version shown at codevector.ai/helm/
curl -fLO https://codevector.ai/helm/codevector-<version>.tgz
tar -xzf codevector-<version>.tgz
ls codevector/templates/
Configuration reference
Every key is documented inline in values.yaml. The most common ones:
| Key | Default | Notes |
|---|---|---|
image.repository | registry.codevector.ai/flotorch/codevector | Override for a private mirror. |
image.tag | latest | Pin a specific app version in production. Current version listed at codevector.ai/helm/. |
replicaCount | 1 | StatefulSet replicas. One PVC per replica. |
secrets.existingSecret | "" | Preferred. Skips the chart-rendered Secret. |
config.gatewayPublicUrl | "" | REQUIRED. Public URL clients reach the gateway at. |
config.logLevel | info | trace, debug, info, warn, or error. |
persistence.size | 2Gi | Usage buffer PVC size per replica. |
persistence.storageClass | "" | Empty means cluster default StorageClass. |
ingress.enabled | false | Off by default. Bring your own controller. |
resources.requests.cpu | 250m | Tune to traffic profile. |
migrate.enabled | true | Pre-install / pre-upgrade hook. |
Pull values.yaml from the chart for the full list:
helm show values codevector/codevector > values.yaml
Day-2 operations
Upgrade to a new app version
Look up the target app version on the Helm repo page, then:
helm repo update
helm upgrade codevector codevector/codevector \
--namespace codevector \
--reuse-values \
--set image.tag=<app-version> # version shown at codevector.ai/helm/
The pre-upgrade hook runs migrations against your Postgres before any new pods roll. Migrations are forward-only and additive within a minor version. If the migration Job fails, the rollout does not proceed.
Scale
Set replicaCount and re-run helm upgrade. Each new replica gets its own ReadWriteOnce PVC for the usage buffer. Rate-limit and budget enforcement stay correct across replicas; Postgres is the source of truth with a documented 1-second cache window.
A HorizontalPodAutoscaler is intentionally not shipped. RWO PVCs and HPA are an awkward combination; if you want autoscaling, add it yourself and pin to a single-zone node pool, or move the usage buffer to RWX storage.
Rotate the KEK (key-encryption key)
-
Patch the Secret to add
KEK_SECONDARYset to the currentKEK_PRIMARYvalue. -
Set
KEK_PRIMARYin the Secret to the new key, then roll the StatefulSet:kubectl -n codevector rollout restart statefulset/codevector -
In the admin console, run the credential re-wrap to re-encrypt every provider credential’s DEK under the new KEK.
-
Once complete, remove
KEK_SECONDARYfrom the Secret and roll again.
Uninstall
helm uninstall codevector --namespace codevector
# PVCs are not deleted by Helm. Remove them only if you intend to throw away the
# on-disk usage buffer state.
kubectl -n codevector delete pvc -l app.kubernetes.io/instance=codevector
Troubleshooting
Migration Job fails
kubectl -n codevector logs job/codevector-migrate
Common causes:
DATABASE_URLwrong: host unreachable, bad password, or missingsslmode=require.- Database role lacks
CREATEon the schema. - Postgres older than 16.
Fix the Secret and re-run helm upgrade. The hook re-runs.
Pods stuck in CrashLoopBackOff
kubectl -n codevector describe pod codevector-0
kubectl -n codevector logs codevector-0 --previous
Look for:
SESSION_SECRET must be exactly 32 chars. Regenerate withopenssl rand -hex 16and update the Secret.KEK_PRIMARY must be at least 32 chars.LICENSE_TOKEN invalid signature. Wrong or expired token.
Ingress is not routing
The chart’s Ingress is controller-agnostic. For ingress-nginx, set ingress.className: nginx. For Traefik, traefik. For the AWS Load Balancer Controller, set ingress.className: alb and add the required ALB annotations under ingress.annotations. Check your controller’s docs for the full annotation list.
Usage buffer is filling up
If Postgres is unreachable for an extended period, each replica buffers usage records on its PVC. Check usage:
kubectl -n codevector exec codevector-0 -- du -sh /var/lib/codevector/usage-buffer
If a PVC is approaching full, increase persistence.size and run helm upgrade. PVCs will expand if the StorageClass supports volume expansion.
Direct downloads
| Artifact | URL |
|---|---|
| Repo page | codevector.ai/helm/ - current chart + app version with a download link |
| Repo index | index.yaml - raw index, lists every published version |
| Chart bundle | https://codevector.ai/helm/codevector-<version>.tgz - substitute the version from the repo page |
For air-gapped installs, mirror the container image to your internal
registry. Pull from registry.codevector.ai using your license token, then
push to your mirror:
# Pick the tag you intend to deploy. "latest" works for evaluation; for
# production, use the current app version shown at
# https://codevector.ai/helm/
TAG=latest
echo "$LICENSE_TOKEN" | docker login registry.codevector.ai -u license --password-stdin
docker pull registry.codevector.ai/flotorch/codevector:$TAG
docker tag registry.codevector.ai/flotorch/codevector:$TAG registry.internal/codevector:$TAG
docker push registry.internal/codevector:$TAG
Then override the image and pull secret in your values file:
image:
repository: registry.internal/codevector
tag: latest # or the pinned version you mirrored
imagePullSecrets:
- name: internal-registry-pull # your own credentials, not the license
The internal registry uses its own auth; the license token is only required during the initial mirror pull, not at runtime inside the cluster.