Self-hosted Okahu¶
Self-hosted Okahu installs the Okahu control plane inside a Kubernetes cluster that you operate. The control plane, the trace store, the evaluation service, and the portal UI all run as workloads inside your cluster. Okahu provides the installer artifact and the container images; your infrastructure runs them. Contact Okahu to receive the installer bundle and the registry credentials needed to pull images.
Deployment options¶
Three deployment paths are supported. Pick the one that matches how much of the surrounding infrastructure you want Okahu's tooling to create for you.
| Option | What it does | Cloud support | Who it is for |
|---|---|---|---|
| 1. Kubernetes deployment only | Runs the installer against an existing Kubernetes cluster, Postgres database, and Azure OpenAI resource that you already own. | Any Kubernetes distribution that can provision a public LoadBalancer service, including Azure AKS, AWS EKS, Google GKE, and on-premises distributions. | Teams that already run production Kubernetes and want to install the Okahu workloads without changing their platform. |
| 2. Full cloud-automated deploy | A set of wrapper scripts creates the cloud resources (resource group, Kubernetes cluster, Postgres server, Azure OpenAI resource, container registry), runs the installer, and writes a state file that later operations scripts read. | Azure AKS today. AWS EKS and Google GKE are planned. | Teams that want a single-command install and do not already have Kubernetes, Postgres, or Azure OpenAI provisioned. |
| 3. Agentic install | A coding agent such as Claude Code or OpenAI Codex drives the Option 2 scripts on your behalf and keeps watch over the install log. | Same cloud support as Option 2. | Teams that already operate their infrastructure through a coding agent and want the agent to perform the install. |
What Okahu provides¶
The following artifacts and credentials are delivered when you contact Okahu. The exact set depends on the deployment option you select.
Two tarballs are referenced throughout the sections below, and the relationship between them matters:
- Install bundle
okahu-standalone-<version>.tar.gzis the file thatinstall.shships inside. Option 1 uses the install bundle directly. - Option 2 installer tarball
okahu-standalone-installer-<version>.tar.gzis a superset. It contains the install bundle underbundle/, plus the Okahu-written Azure provisioning and operations scripts underscripts/, plus aconfig.example.yamltemplate. Option 2 and Option 3 use the installer tarball.
A customer installing with Option 2 or Option 3 does not need the install bundle separately; it is embedded in the installer tarball they receive.
For every option¶
| Artifact | Description |
|---|---|
Install bundle okahu-standalone-<version>.tar.gz |
Archive containing install.sh, the per-chart Helm values files, the KubeRay cluster manifest, the Postgres schema bootstrap Job, and the installer README. This is the content Option 1 operates on directly, and is embedded inside the Option 2 installer tarball. |
| Image access (one of two paths) | The container images that back the install have to come from somewhere the cluster can reach. Two paths are supported, and both are first-class. (a) Pull from the Okahu-hosted registry. Okahu issues a registry username and token that install.sh writes into the okahu-registry imagePullSecret. (b) Pull from your own registry. You mirror the images into a registry you already run (Azure Container Registry, Amazon ECR, Harbor, Quay, Nexus, GCP Artifact Registry) and point install.sh at that registry with OKAHU_REGISTRY_HOST. For Azure AKS, the ACR path is often the simpler one because AKS can pull from an attached ACR using its managed identity, with no imagePullSecret and no long-lived token to rotate. Okahu provides the image archives for the mirror; see Additional artifacts for a private-registry install. |
Additional artifacts for Option 2¶
| Artifact | Description |
|---|---|
Option 2 installer tarball okahu-standalone-installer-<version>.tar.gz |
Archive containing the install bundle above, the Azure provisioning and operations scripts (full-deploy.sh, preflight-setup.sh, deploy.sh, test.sh, status.sh, redeploy.sh, rotate-secret.sh, teardown.sh, troubleshoot.sh, lib.sh), and a config.example.yaml template. |
release.tag value |
Pins the backend chart and image version to a release Okahu has validated against the installer bundle. Goes into the release.tag field of your YAML configuration. |
portal_ux.image_tag value |
Pins the portal UI image to a known-good tag. The default latest tag is not recommended for production because it moves on every build. Goes into the portal_ux.image_tag field of your YAML configuration. |
portal_ux.source_registry value |
The source container reference that the deploy.sh script imports the pinned portal UI image from into your per-cluster Azure Container Registry. Goes into the portal_ux.source_registry field of your YAML configuration. |
Additional artifacts for Option 3¶
| Artifact | Description |
|---|---|
| Private Claude Code plugin | Marketplace reference and install one-liner for the Okahu-maintained plugin that packages the Option 2 scripts as Claude Code skills, exposing /ok-full-deploy, /ok-deploy-aks, and /ok-preflight-setup. Delivered to teams that use Claude Code. |
| Agent-specific instructions | For OpenAI Codex CLI or another shell-driving coding agent, Okahu provides the Option 2 installer tarball plus a short reference prompt that the agent uses to run full-deploy.sh and interpret the install log. |
Additional artifacts for a private-registry install¶
The artifacts below apply whenever install.sh pulls from a registry you operate, rather than from the Okahu-hosted registry. Common cases include an Azure Container Registry attached to the AKS cluster, Amazon ECR, Harbor, Quay, Nexus, GCP Artifact Registry, or any registry inside an air-gapped network perimeter. The default install path does not need these artifacts.
| Artifact | Description |
|---|---|
| Pre-pulled container images | A set of OCI image archives for every chart in the release, suitable for docker load, skopeo copy, az acr import, or aws ecr-public batch-copy-image. You push them into your registry under the paths install.sh expects. |
| Chart archives | The Helm chart .tgz files for every release component, so install.sh can resolve charts from a local path instead of the public OCI registry. |
| Mirror-aware installer bundle | A copy of the install bundle whose install.sh honors OKAHU_REGISTRY_HOST pointed at your internal registry, so no pod attempts an outbound image pull. |
Loading images into Azure Container Registry¶
The 11 Okahu container images and 11 Helm charts need to be mirrored into the ACR before install.sh runs. Two paths are supported depending on whether the ACR can reach the Okahu-hosted registry at mirror time.
Path 1: az acr import (ACR has temporary Internet access to Okahu's registry)
Azure performs the copy from Okahu's registry to your ACR through its control plane, so the operator's machine does not need to pull the images locally. The ACR itself needs outbound connectivity to the Okahu-hosted registry for the duration of the import. The AKS cluster can then be fully air-gapped afterward.
export ACR=myacr # Your Azure Container Registry name
export OKAHU_REGISTRY_USER=<supplied by Okahu>
export OKAHU_REGISTRY_TOKEN=<supplied by Okahu>
export RELEASE_TAG=<supplied by Okahu> # Backend chart and image version
export PORTAL_UX_TAG=<supplied by Okahu> # portal-ux image tag
export PORTAL_UX_CHART=<supplied by Okahu> # portal-ux chart version
# Backend images (10 total)
for svc in okahu-data okahu-eval-api okahu-graphs okahu-ingestion okahu-mcp \
okahu-ml-analysis okahu-provisioning okahu-scheduler okahu-sre-agent okahu-ray; do
az acr import --name "$ACR" \
--source "okahu.jfrog.io/containers/okahu-cloud/standalone/${svc}:${RELEASE_TAG}" \
--image "containers/okahu-cloud/standalone/${svc}:${RELEASE_TAG}" \
--username "$OKAHU_REGISTRY_USER" --password "$OKAHU_REGISTRY_TOKEN"
done
# portal-ux image (eleventh, carries its own tag)
az acr import --name "$ACR" \
--source "okahu.jfrog.io/containers/okahu-cloud/standalone/portal-ux:${PORTAL_UX_TAG}" \
--image "containers/okahu-cloud/standalone/portal-ux:${PORTAL_UX_TAG}" \
--username "$OKAHU_REGISTRY_USER" --password "$OKAHU_REGISTRY_TOKEN"
# Helm charts, 10 at the release tag plus portal-ux at its own chart version
helm registry login "${ACR}.azurecr.io" \
--username 00000000-0000-0000-0000-000000000000 \
--password "$(az acr login --name "$ACR" --expose-token --output tsv --query accessToken)"
mkdir -p ./charts
for chart in okahu-shared okahu-data okahu-graphs okahu-ingestion okahu-mcp \
okahu-ml-analysis okahu-provisioning okahu-scheduler okahu-sre-agent eval-api; do
helm pull "oci://okahu.jfrog.io/containers/okahu-cloud/charts/${chart}" \
--version "$RELEASE_TAG" --destination ./charts
helm push "./charts/${chart}-${RELEASE_TAG}.tgz" \
"oci://${ACR}.azurecr.io/containers/okahu-cloud/charts"
done
helm pull "oci://okahu.jfrog.io/containers/okahu-cloud/charts/portal-ux" \
--version "$PORTAL_UX_CHART" --destination ./charts
helm push "./charts/portal-ux-${PORTAL_UX_CHART}.tgz" \
"oci://${ACR}.azurecr.io/containers/okahu-cloud/charts"
Path 2: OCI archives and skopeo (ACR has no outbound Internet access)
Request the pre-pulled image archives and chart .tgz files from Okahu, transfer them across the air gap, then push into the ACR using skopeo (for images) and helm push (for charts).
# On a connected workstation, transfer /airgap-okahu-release/*.tar and /airgap-okahu-release/charts/*.tgz
# across the air gap. On the air-gapped side with ACR access:
export ACR=myacr
helm registry login "${ACR}.azurecr.io" \
--username 00000000-0000-0000-0000-000000000000 \
--password "$(az acr login --name "$ACR" --expose-token --output tsv --query accessToken)"
for img in /airgap-okahu-release/images/*.tar; do
skopeo copy "oci-archive:${img}" \
"docker://${ACR}.azurecr.io/containers/okahu-cloud/standalone/$(basename "$img" .tar)"
done
for chart in /airgap-okahu-release/charts/*.tgz; do
helm push "$chart" "oci://${ACR}.azurecr.io/containers/okahu-cloud/charts"
done
Attach the ACR to AKS so the cluster can pull without an imagePullSecret
With the ACR attached, AKS authenticates to the ACR using its managed identity. The okahu-registry imagePullSecret that install.sh writes is still populated but becomes redundant for the pull itself.
Run install.sh against your ACR
OKAHU_REGISTRY_HOST="${ACR}.azurecr.io" \
OKAHU_REGISTRY_PATH=containers/okahu-cloud \
OKAHU_REGISTRY_USER=00000000-0000-0000-0000-000000000000 \
OKAHU_REGISTRY_TOKEN="$(az acr login --name "$ACR" --expose-token --output tsv --query accessToken)" \
./install.sh \
--release "$RELEASE_TAG" \
--portal-ux-version "$PORTAL_UX_CHART" \
--pg-url "postgresql://..." \
--azure-openai-endpoint "https://YOUR_AOAI.openai.azure.com/" \
--azure-openai-key "$AOAI_KEY" \
--azure-openai-model "gpt-4.1"
Upstream dependencies (fully air-gapped only)
The installer also pulls three upstream Helm charts directly from the Internet: Traefik (https://traefik.github.io/charts), cert-manager (https://charts.jetstack.io), and KubeRay (https://ray-project.github.io/kuberay-helm/). A fully air-gapped install needs those three chart archives plus their referenced images mirrored into the ACR as well. Contact Okahu for a mirror-aware installer bundle that bundles the upstream charts and patches install.sh to resolve them locally.
Delivery and support¶
Okahu CX delivers the artifacts above over a channel agreed with your team (private download link, cloud storage share, or email attachment) and sends a notification when a new version ships. Installation assistance, cleanup commands for trailing state at uninstall time, and support for additional LLM providers are all available through the same channel. Contact Okahu to open the conversation.
Common prerequisites¶
Every option requires the following four items in addition to the artifacts Okahu provides. Option-specific prerequisites appear in each section below.
- Azure OpenAI with a
gpt-4.1deployment at a Standard, GlobalStandard, or DataZoneStandard SKU with sufficient tokens-per-minute capacity for your workload. The installer uses the literal deployment namegpt-4.1because the evaluation service references the deployment by that exact name. - A Postgres 16 database that the installer can use exclusively. The installer creates schemas and tables inside the database you supply; it does not share tables with another application. Postgres 15 and 14 are not supported.
- Local tools on the operator's PATH:
kubectl,helmversion 3.8 or later for OCI chart support,python3,curl, andtar. - The artifacts listed in What Okahu provides: at minimum the install bundle and image-pull credentials, plus the Option 2 installer tarball and pinned configuration values if you are using Option 2 or 3.
Option 1. Kubernetes deployment only¶
Option 1 installs the Okahu workloads into a Kubernetes cluster that already exists. You own the cluster, the Postgres server, and the Azure OpenAI resource; the installer deploys only the Okahu workloads, the KubeRay cluster used by the evaluation service, cert-manager if HTTPS is enabled, and the Traefik ingress.
Prerequisites¶
In addition to the common prerequisites, Option 1 requires:
- A Kubernetes cluster whose current
kubectlcontext points at the target. The cluster must support provisioning a public LoadBalancer service, because the Traefik ingress acquires a public IP that way. - A Postgres 16 database that the installer can reach from inside the cluster, with an administrative user whose connection string is passed to
--pg-url. - An Azure OpenAI resource whose endpoint, API key, and
gpt-4.1deployment name are known.
Install command¶
Extract the install bundle and run the installer. The following command installs with the default authentication mode (simple, which configures a shared bearer token):
tar xzf okahu-standalone-<version>.tar.gz
cd okahu-standalone-<version>
./install.sh \
--pg-url "postgresql://USER:PASS@YOUR_PG_HOST:5432/DB?sslmode=require" \
--registry-user "YOUR_REGISTRY_USERNAME" \
--registry-token "YOUR_REGISTRY_TOKEN" \
--azure-openai-endpoint "https://YOUR_AOAI.openai.azure.com/" \
--azure-openai-key "YOUR_AOAI_KEY" \
--azure-openai-model "gpt-4.1"
When the installer finishes, it prints the LoadBalancer address, the tenant identifier, the shared authentication token (for simple mode), and the first API key. Save that information. The API key is stored only as a hash, so a subsequent re-run cannot display the plaintext value a second time.
Enabling HTTPS and Entra ID sign-in¶
To expose the portal over HTTPS with a Let's Encrypt certificate, and to require Microsoft Entra ID sign-in rather than a shared bearer token, add the following flags to the install command.
./install.sh \
--pg-url "postgresql://USER:PASS@YOUR_PG_HOST:5432/DB?sslmode=require" \
--registry-user "YOUR_REGISTRY_USERNAME" \
--registry-token "YOUR_REGISTRY_TOKEN" \
--azure-openai-endpoint "https://YOUR_AOAI.openai.azure.com/" \
--azure-openai-key "YOUR_AOAI_KEY" \
--azure-openai-model "gpt-4.1" \
--hostname "okahu.your-domain.example" \
--acme-email "ops@your-company.example" \
--auth-provider entra \
--azure-ad-tenant-id "YOUR_ENTRA_TENANT_ID" \
--azure-ad-client-id "YOUR_ENTRA_APP_CLIENT_ID"
Each new flag has a specific purpose. The following table explains why each one is required.
| Flag | Purpose |
|---|---|
--hostname |
Declares the public DNS name that the portal and APIs will serve under. The installer uses this value to request a Let's Encrypt certificate through cert-manager, to configure the Traefik router rules, and to construct the default Entra redirect URI. The DNS name must resolve to the LoadBalancer's public IP before the installer runs; the ACME HTTP challenge fails otherwise. |
--acme-email |
Registers an ACME account with Let's Encrypt. Let's Encrypt uses the address for certificate expiry notifications and policy announcements. The flag is required whenever --hostname is supplied, because every Let's Encrypt account must have a registered contact. |
--auth-provider entra |
Switches the control plane and the portal UI from the default shared-bearer mode to Microsoft Entra ID. In Entra mode, each user signs in individually, the portal exchanges the authorization code for access tokens through MSAL, and the backend services validate the tokens against Entra. |
--azure-ad-tenant-id |
Identifies the Entra directory (tenant) that owns the app registration. The backend services use the tenant GUID to look up the signing keys that validate incoming access tokens. |
--azure-ad-client-id |
Identifies the Entra app registration that the portal uses to sign users in. The portal sends this value to Entra as the OAuth 2.0 client_id parameter, and the backend services use it to validate the aud claim on every access token. |
Every install.sh flag¶
The complete flag set is listed below. Flags marked Required must be supplied either on the command line or through the matching environment variable. All others have working defaults.
Required¶
| Flag | Environment variable | Description |
|---|---|---|
--pg-url URL |
OKAHU_PG_URL |
Postgres connection string. The database must be exclusive to Okahu. |
--registry-user U |
OKAHU_REGISTRY_USER |
Username issued by Okahu for pulling container images. |
--registry-token T |
OKAHU_REGISTRY_TOKEN |
Token issued by Okahu for pulling container images. |
--azure-openai-endpoint URL |
OKAHU_AZURE_OPENAI_ENDPOINT |
Base URL of the Azure OpenAI resource. |
--azure-openai-key K |
OKAHU_AZURE_OPENAI_KEY |
API key for the Azure OpenAI resource. |
--azure-openai-model M |
OKAHU_AZURE_OPENAI_MODEL |
Name of the Azure OpenAI deployment. Set to gpt-4.1. |
Versioning¶
| Flag | Environment variable | Description |
|---|---|---|
--release V |
OKAHU_RELEASE |
Pins the Okahu chart and image version. Defaults to the newest stable release. |
--portal-ux-version V |
OKAHU_PORTAL_UX_CHART_VERSION |
Pins the portal-ux chart version. Defaults to the newest stable release. |
Authentication¶
| Flag | Environment variable | Description |
|---|---|---|
--auth-provider P |
OKAHU_AUTH_PROVIDER |
Selects simple (default, shared bearer token) or entra (Microsoft Entra ID sign-in). |
--simple-auth-secret S |
OKAHU_SIMPLE_AUTH_SECRET |
Simple mode only. The shared bearer token value. Generated when omitted; reused across re-runs. |
--simple-auth-email E |
OKAHU_SIMPLE_AUTH_EMAIL |
Simple mode only. The administrator email recorded on the first tenant. Default: admin@okahu.local. |
--azure-ad-tenant-id G |
OKAHU_AZURE_AD_TENANT_ID |
Entra mode only. Directory (tenant) GUID. |
--azure-ad-client-id G |
OKAHU_AZURE_AD_CLIENT_ID |
Entra mode only. App registration client GUID. |
--azure-ad-authority-host H |
OKAHU_AZURE_AD_AUTHORITY_HOST |
Entra mode only. OAuth authority hostname. Default: login.microsoftonline.com. |
--admin-token T |
OKAHU_ADMIN_TOKEN |
Entra mode only. An administrator's Entra access token used by the installer for the tenant-create and API-key-mint bootstrap calls. |
--azure-redirect-uri U |
OKAHU_AZURE_REDIRECT_URI |
Entra mode only. The exact redirect URI registered on the app. Defaults to https://<hostname>/en. |
--skip-entra-app-update |
OKAHU_SKIP_ENTRA_APP_UPDATE |
Entra mode only. Set when the operator does not have permission to update the app registration; the operator must register the redirect URI manually. |
HTTPS and DNS¶
| Flag | Environment variable | Description |
|---|---|---|
--hostname H |
OKAHU_HOSTNAME |
Public DNS name. Enables HTTPS and a Let's Encrypt certificate. Required when --auth-provider is entra. |
--acme-email E |
OKAHU_ACME_EMAIL |
Contact address for the ACME account. Required whenever --hostname is set. |
--acme-server U |
OKAHU_ACME_SERVER |
ACME endpoint. Default: Let's Encrypt production. |
--dns-label L |
OKAHU_DNS_LABEL |
Azure only. Asks AKS to assign this DNS label to the LoadBalancer's public IP, so the installer can derive a <label>.<region>.cloudapp.azure.com hostname. |
Tenancy¶
| Flag | Environment variable | Description |
|---|---|---|
--okahu-tenant-id T |
OKAHU_TENANT_ID |
Pins the tenant the services resolve to. Required only when the database holds more than one tenant. |
--tenant-display-name N |
OKAHU_TENANT_DISPLAY_NAME |
Display name for the first tenant. Default: Okahu. |
Workloads and cluster¶
| Flag | Environment variable | Description |
|---|---|---|
--namespace NS |
OKAHU_NAMESPACE |
Kubernetes namespace for the main Okahu workloads. Default: okahu. |
--ray-namespace NS |
OKAHU_RAY_NAMESPACE |
Kubernetes namespace for the KubeRay cluster used by the evaluation service. Default: okahu-ray. |
--ray-cluster-name N |
OKAHU_RAY_CLUSTER_NAME |
Name of the RayCluster resource. Default: okahu-eval-raycluster. |
--ray-workers N |
OKAHU_RAY_WORKERS |
Number of Ray worker pods. Default: 2. |
--kubeconfig PATH |
KUBECONFIG |
Path to the kubeconfig file. Default: the current context. |
--azure-api-version V |
OKAHU_AZURE_API_VERSION |
Azure OpenAI API version. Default: 2024-10-21. The value must match a version supported by your Azure OpenAI resource. |
Option 2. Full cloud-automated deploy¶
Option 2 creates the surrounding cloud resources (resource group, Kubernetes cluster, Postgres server, Azure OpenAI resource, container registry) and then runs the installer with the correct arguments. The entry point reads a single YAML configuration file so that re-runs are deterministic and version-controllable.
2a. Azure AKS¶
Option 2a provisions an Azure AKS cluster, an Azure Database for PostgreSQL Flexible Server, an Azure OpenAI resource with a gpt-4.1 deployment, and an Azure Container Registry attached to the cluster. The entry point runs the installer and writes a .env.<prefix> file that other operations scripts consume.
Prerequisites¶
In addition to the common prerequisites, Option 2a requires:
- An Azure subscription on which the operator has the Owner or Contributor role.
- The Azure CLI (
az) version 2.56 or later, logged in withaz loginand set to the target subscription withaz account set --subscription <id>. - Permission to update Entra app registrations (the
Application.ReadWrite.AllMicrosoft Graph permission, or equivalent through the Cloud Application Administrator role). The installer uses this permission to add the portal's redirect URI to the app registration. - The
pyyamlPython package installed, so that the entry point can parse the YAML configuration. - Sufficient quota in the target region for a
Standard_D4s_v5node pool (at least 12 vCPUs) and for thegpt-4.1Azure OpenAI SKU you selected.
Install bundle layout¶
The installer archive that Okahu provides for Option 2a has the following layout.
okahu-standalone-installer-<version>/
├── README.md
├── config.example.yaml
├── bundle/ # install.sh and the Helm values files
├── scripts/
│ ├── full-deploy.sh # Entry point; runs preflight-setup then deploy
│ ├── preflight-setup.sh # One-time per Azure subscription and Entra tenant
│ ├── deploy.sh # Creates the cloud resources and runs install.sh
│ ├── test.sh # 17-case smoke test, with an HTML report
│ ├── status.sh # Cluster snapshot
│ ├── redeploy.sh # Helm upgrade to a new release tag
│ ├── rotate-secret.sh # Rotates the shared bearer token (simple mode only)
│ ├── teardown.sh # Deletes the Azure resource group
│ ├── troubleshoot.sh # Collects a diagnostic bundle
│ └── lib.sh
└── config/ # Where operator-written YAML configurations live
Install command¶
tar xzf okahu-standalone-installer-<version>.tar.gz
cd okahu-standalone-installer-<version>
cp config.example.yaml config/prod.yaml
# Edit config/prod.yaml. Set prefix, hostname, dns_label, redirect_uri,
# auth.entra.tenant_id, auth.entra.client_id, portal_ux values, and release.
./scripts/full-deploy.sh --config config/prod.yaml
The entry point completes in approximately 25 minutes. On success, it writes .env.prod with the LoadBalancer address, tenant identifier, API key, and the names of every Azure resource it created.
Configuration schema¶
Each key in the configuration file maps to one or more environment variables that the underlying installer and scripts read. The schema is as follows.
prefix: prod # Used as the prefix for every Azure resource name
region: eastus # Azure region for every resource
aks:
node_count: 3 # Node count for the system node pool
node_sku: Standard_D4s_v5 # VM size for the system node pool
auth:
provider: entra # Either "entra" or "simple"
hostname: prod-okahu.eastus.cloudapp.azure.com # Public DNS name. See the hostname flag description below.
dns_label: prod-okahu # Label assigned to the LoadBalancer public IP so Azure assigns the above hostname
acme_email: ops@your-company.example # Let's Encrypt contact
acme_server: https://acme-v02.api.letsencrypt.org/directory # ACME endpoint; defaults to Let's Encrypt production
redirect_uri: https://prod-okahu.eastus.cloudapp.azure.com/en # Entra app redirect URI
entra:
tenant_id: YOUR_ENTRA_TENANT_ID # Directory (tenant) GUID
client_id: YOUR_ENTRA_APP_CLIENT_ID # App registration client GUID
portal_ux:
acr_name: prodokahuacr # Azure Container Registry name
image_repo: prodokahuacr.azurecr.io/portal-ux # Pinned portal-ux image repository
image_tag: <image tag supplied by Okahu> # Pinned portal-ux image tag
source_registry: <mirror source supplied by Okahu> # Source registry that the deploy script imports the portal-ux image from
release:
tag: <release tag supplied by Okahu> # Pins the backend chart and image version
To add a second cluster, copy the YAML file and change the prefix, acr_name, hostname, dns_label, and redirect_uri values.
Operations¶
The operations scripts listed below are part of the Option 2a installer tarball that Okahu provides. They are not part of the upstream install.sh bundle used by Option 1; they are wrappers that Okahu ships specifically to automate the lifecycle of a cloud-automated deploy. Each script reads the same YAML configuration file.
./scripts/test.sh --config config/prod.yaml
./scripts/status.sh --config config/prod.yaml
./scripts/redeploy.sh --config config/prod.yaml
./scripts/rotate-secret.sh --config config/prod.yaml
./scripts/teardown.sh --config config/prod.yaml --yes
| Script | What it does | When to run it |
|---|---|---|
test.sh |
Runs a 17-case smoke test suite against the live cluster: health endpoints for every service, a positive and negative authentication check, a tenant and API-key readback, an ingest round-trip, and a Kubernetes readiness probe. Writes a timestamped HTML report under logs/ and opens it in the operator's default browser. |
After every install, after every redeploy, and whenever a cluster behavior needs a quick confirmation. |
status.sh |
Prints a snapshot of the cluster: namespaces, deployments and their replica counts, the Traefik LoadBalancer address, the RayCluster state, and the Postgres server state. Read-only. | When investigating cluster health between tests. |
redeploy.sh |
Re-runs install.sh against the existing cluster, skipping all Azure provisioning. Used to upgrade the Okahu release tag by setting a new release.tag in the configuration, to re-apply a changed Helm values override, or to recover from a partial install. |
When upgrading to a new release, when a chart value changes, or when install.sh left a release in a half-applied state. |
rotate-secret.sh |
Simple authentication mode only. Generates a new 32-character shared bearer token, patches the okahu-secrets Kubernetes Secret, and triggers a rolling restart of every backend deployment so pods pick up the new value. Updates .env.<prefix> with the new token. Tenant API keys (the okh_… values) are not affected by rotation. Entra authentication mode has no shared token to rotate; access tokens are issued per user by Microsoft Entra. The same rotation can be performed by passing --simple-auth-secret <new-value> to install.sh (or exporting OKAHU_SIMPLE_AUTH_SECRET before redeploy.sh); the installer detects the change, updates the Secret, and restarts the pods on its own. The rotate-secret.sh wrapper is the single-command convenience path for the same operation. |
At the operator's rotation cadence for the simple provider, or when the shared token may have been exposed. |
teardown.sh |
Deletes the Azure resource group, which cascades the AKS cluster, Postgres server, Azure OpenAI resource, and container registry. Moves .env.<prefix> aside so later scripts do not treat the cluster as live. The --yes flag skips the interactive confirmation prompt. |
When decommissioning a cluster. |
2b. AWS EKS¶
Support for AWS EKS is planned and not yet available. Contact Okahu to register interest; this signals demand and helps prioritize the work. In the meantime, teams on EKS can use Option 1 today by provisioning the EKS cluster, Postgres database, and Azure OpenAI resource themselves and then running install.sh directly.
2c. Google GKE¶
Support for Google GKE is planned and not yet available. Contact Okahu to register interest. Teams on GKE can use Option 1 today using the same approach as EKS.
Option 3. Agentic install¶
Option 3 is the same deploy as Option 2, driven by a coding agent instead of a human operator. The agent reads the YAML configuration, runs the scripts, watches the deploy log, and surfaces errors in context.
The scripts contain no LLM calls. The agent operates above the scripts, driving them from the shell; the scripts themselves are deterministic bash plus az, kubectl, helm, curl, and python3.
Claude Code¶
Okahu provides a private Claude Code plugin that packages the Option 2 scripts as Claude Code skills. The plugin exposes three slash commands: /ok-full-deploy, /ok-deploy-aks, and /ok-preflight-setup. Contact Okahu to request access and installation instructions.
OpenAI Codex CLI and other coding agents¶
Any agent that can run shell commands can drive the Option 2 scripts without additional packaging. Install the Option 2 installer bundle on the agent's host, then point the agent at ./scripts/full-deploy.sh --config config/<prefix>.yaml. The agent needs read access to the configuration file, write access to the working directory for log files, and the same Azure, Entra, and Kubernetes credentials that an operator would use.
Limitations¶
LLM provider¶
Azure OpenAI with a gpt-4.1 deployment is required today. Direct OpenAI, Amazon Bedrock, and Anthropic are not supported. Contact Okahu if another provider is required for your deployment.
Cloud coverage¶
Option 2 supports Azure AKS today. AWS EKS and Google GKE are planned. Option 1 runs on any Kubernetes distribution and can be used on EKS and GKE now.
Private-registry and air-gapped environments¶
The installer supports pulling images from any registry you operate, not only the Okahu-hosted registry. Set OKAHU_REGISTRY_HOST to the hostname of your own registry (for example <name>.azurecr.io, <accountid>.dkr.ecr.<region>.amazonaws.com, or your Harbor instance), import the images Okahu provides, and the install runs with no outbound dependency on the Okahu registry. This is a common choice for enterprises that require every production image to live inside their own control plane, whether or not the cluster is air-gapped. Contact Okahu to arrange a shipment of pre-pulled images and chart archives.
Versioning and upgrades¶
Each install is pinned to the bundle version that the operator downloaded. Okahu notifies you when a new bundle is published. To upgrade an Option 2 install, edit the release.tag value in the configuration file and run ./scripts/redeploy.sh --config config/prod.yaml. To upgrade an Option 1 install, pass --release <new-version> to install.sh.
Uninstall completeness¶
The teardown script deletes the Azure resource group, which cascades the AKS cluster, the Postgres server, the Azure OpenAI resource, and the container registry. Three artifacts are not removed and must be cleaned up separately if a zero-trailing-state uninstall is required:
- The Entra app registration redirect URI that the installer added. Remove it in the Azure Portal under App registrations → Authentication → Single-page application, or contact Okahu for the cleanup command.
- The Azure point-in-time Postgres backups, which Azure retains per the server's retention policy. Delete them in the Azure Portal if you want them removed.
- The local
kubectlcontext, cluster, and user entries, which remain in~/.kube/config. Remove them withkubectl config delete-context,kubectl config delete-cluster, andkubectl config delete-user.
Support¶
Contact Okahu for the installer bundle, image-pull credentials, air-gapped shipments, support for additional LLM providers, and installation assistance.