Skip to content

Production deployment

A production deployment requires database provisioning, secrets, access control, network policy, storage, and backups.

It is recommended that okapictl be installed from PyPI before starting the deployment:

python -m pip install okapi-ctl

For command options and controller versioning guidance, see the okapictl reference.

Helm charts are published with every Okapi release as OCI artifacts under oci://ghcr.io/okapi-core/charts. The Kubernetes installation deploys only Okapi: ops, ingester, oscar, and web. PostgreSQL and ClickHouse are production dependencies and must be deployed and operated separately.

Prerequisites

You’ll need:

  • a Kubernetes cluster and a configured kubectl context;
  • Helm 3 with OCI registry support;
  • PostgreSQL and ClickHouse reachable through Kubernetes Services;
  • the matching PostgreSQL and ClickHouse credentials;
  • an OpenAI API key for Oscar, if AI-assisted investigation is required; and
  • okapictl installed at the same release as the Okapi charts.

Before installing Okapi, configure PostgreSQL and ClickHouse as described in the PostgreSQL configuration guide and the ClickHouse configuration guide. This deployment guide assumes those databases, users, permissions, and ClickHouse cluster settings are already in place.

Select the target context and create the namespace:

kubectl config use-context <context-name>
kubectl create namespace okapi --dry-run=client -o yaml | kubectl apply -f -

Create the reserved Secrets

Create these Secrets in the Okapi namespace. The Secret names and keys form the interface between the deployment configuration and the Helm charts:

kubectl -n okapi create secret generic okapi-clickhouse \
  --from-literal=username=<clickhouse-user> \
  --from-literal=password='<clickhouse-password>'

kubectl -n okapi create secret generic okapi-postgres \
  --from-literal=migration-username=<migration-user> \
  --from-literal=migration-password='<migration-password>' \
  --from-literal=web-username=<web-user> \
  --from-literal=web-password='<web-password>' \
  --from-literal=oscar-username=<oscar-user> \
  --from-literal=oscar-password='<oscar-password>'

kubectl -n okapi create secret generic okapi-openai \
  --from-literal=api-key='<openai-api-key>'

The ClickHouse Secret contains the client account used by ops and ingester; it is not used for ClickHouse inter-node authentication. The PostgreSQL Secret contains three accounts: migration, Web runtime, and Oscar runtime. The OpenAI Secret is only needed when Oscar’s AI-assisted features are enabled.

Do not commit credentials to a repository. Store them in Kubernetes Secrets or an external secret manager.

Verify that the Secrets exist without printing their values:

kubectl -n okapi get secret okapi-clickhouse okapi-postgres okapi-openai

for item in \
  okapi-clickhouse:username \
  okapi-clickhouse:password \
  okapi-postgres:migration-username \
  okapi-postgres:migration-password \
  okapi-postgres:web-username \
  okapi-postgres:web-password \
  okapi-postgres:oscar-username \
  okapi-postgres:oscar-password \
  okapi-openai:api-key; do
  secret="${item%%:*}"
  key="${item#*:}"
  kubectl -n okapi get secret "$secret" \
    -o go-template="{{if not (index .data \"$key\")}}missing $secret/$key{{end}}"
done

Prepare values

Create a directory containing these four files:

ops-values.yaml
ingester-values.yaml
oscar-values.yaml
web-values.yaml

Use the version-matched templates bundled with okapictl, then replace the placeholders with the PostgreSQL and ClickHouse Service names, database names, and Secret references. The important settings are:

ops-values.yaml:

clickhouse:
  host: okapi-clickhouse
  port: 8123
  existingSecret: okapi-clickhouse
  usernameKey: username
  passwordKey: password

postgres:
  url: jdbc:postgresql://<postgres-service>:5432/okapi_oscar?currentSchema=okapi_web
  existingSecret: okapi-postgres
  usernameKey: migration-username
  passwordKey: migration-password

ingester-values.yaml:

clickhouse:
  host: okapi-clickhouse
  port: 8123
  existingSecret: okapi-clickhouse
  usernameKey: username
  passwordKey: password

web-values.yaml:

postgres:
  host: <postgres-service>
  port: 5432
  database: okapi_oscar
  schema: okapi_web
  existingSecret: okapi-postgres
  usernameKey: web-username
  passwordKey: web-password

oscar-values.yaml:

postgres:
  host: <postgres-service>
  port: 5432
  database: okapi_oscar
  schema: okapi_oscar
  existingSecret: okapi-postgres
  usernameKey: oscar-username
  passwordKey: oscar-password

openai:
  existingSecret: okapi-openai
  apiKeyKey: api-key

Keep the image repository and tag pinned to the same Okapi release across all four files. If you change a Secret key, database name, schema name, or Service name, update the corresponding value in every affected file.

Install Okapi

Point okapictl to the values directory:

okapictl install --k8s \
  --namespace okapi \
  --values-dir ./okapi-values \
  --timeout 900

The controller installs the charts in dependency order:

ops → ingester → oscar → web

It uses the current kubectl context and does not change cluster selection or install PostgreSQL or ClickHouse. To check the resulting workloads:

kubectl -n okapi get pods,deployments,jobs
helm -n okapi list
kubectl -n okapi get events --sort-by=.lastTimestamp

Admins note

Why databases are external

Okapi does not prescribe a production PostgreSQL or ClickHouse topology. Capacity, availability, storage, backup, and recovery requirements vary with telemetry volume and organizational policy. Operate and scale both databases independently, and use Okapi’s PostgreSQL and ClickHouse dashboards to monitor throughput, latency, and resource usage.