Install on OpenShift
This page installs Olympusx AI on OpenShift through the Olympusx AI operator: the catalog, the operator, and one Olympus resource that the operator turns into a running platform. Plan on about an hour, most of it waiting for images. Each step gives the oc command; where the OpenShift web console does the same thing, its path is named too.
Prerequisites
Section titled “Prerequisites”-
OpenShift 4.20 or later, and an account with cluster-admin. The operator needs Kubernetes 1.33.
-
oc, logged in as that account. -
linux/amd64worker nodes for the platform. -
Room for the platform: about 5 CPU and 12 GiB of memory in requests, before any model serving.
-
Storage: a ReadWriteOnce StorageClass for the database (three instances, each with a 20 GiB and a 10 GiB volume), and a default StorageClass for the object store’s 50 GiB volume.
oc get storageclassmarks the default. On OpenShift Data Foundation, use the Ceph RBD class for the database. -
The PostgreSQL operator, installed for all namespaces (Requirements).
-
The registry credential from your subscription.
-
An SMTP relay the cluster can reach, for invitations.
-
Two hostnames directly under the apps domain. The Routes use edge TLS with the router’s default certificate, which covers one label deep. Print the apps domain:
oc get ingresses.config/cluster -o jsonpath='{.spec.domain}{"\n"}'Then use, for example,
olympus.<apps-domain>for the console andolympus-api.<apps-domain>for the gateway. The cluster’s wildcard DNS already resolves them.
Step 1: Create the pull secret in three namespaces
Section titled “Step 1: Create the pull secret in three namespaces”Three things pull images, in three namespaces, and a Secret does not cross a namespace boundary:
| Namespace | What pulls | Without the Secret |
|---|---|---|
openshift-marketplace |
The catalog | The catalog never reaches READY, and no tile appears |
openshift-operators |
The operator | The operator stays at Installing |
olympus |
The platform | The operator installs; every platform pod fails its pull |
for ns in openshift-marketplace openshift-operators olympus; do oc create namespace "$ns" 2>/dev/null || true oc -n "$ns" create secret docker-registry <pull-secret> \ --docker-server=<registry-host> \ --docker-username=<registry-username> \ --docker-password=<registry-token> \ --dry-run=client -o yaml | oc apply -f -donecreate | apply replaces an older Secret of the same name. A plain oc create secret fails with AlreadyExists and leaves an old token in place.
In the web console: choose each namespace in the Project list, then Workloads › Secrets › Create › Image pull secret.
Step 2: Add the catalog and subscribe
Section titled “Step 2: Add the catalog and subscribe”The Olympusx AI operator is distributed through its own catalog, not a public listing. The catalog image reference comes with your subscription.
Save this as olympus-catalog.yaml:
apiVersion: operators.coreos.com/v1alpha1kind: CatalogSourcemetadata: name: olympus-operators namespace: openshift-marketplacespec: sourceType: grpc image: <catalog-image> displayName: Olympusx AI publisher: Olympusx.ai secrets: - <pull-secret> updateStrategy: registryPoll: interval: 30m---apiVersion: operators.coreos.com/v1alpha1kind: Subscriptionmetadata: name: olympus-operator namespace: openshift-operatorsspec: channel: stable name: olympus-operator source: olympus-operators sourceNamespace: openshift-marketplace installPlanApproval: Automaticoc apply -f olympus-catalog.yamlKeep the names as written. The Subscription finds the catalog by source and sourceNamespace; a sourceNamespace with no matching CatalogSource never resolves and reports no error. The operator goes in openshift-operators because it watches all namespaces.
Approval. Automatic installs at once and applies newer versions the catalog offers. Manual holds every install and upgrade, this first one included, until someone approves it; production clusters usually take Manual so an upgrade waits for its change window.
Wait for the catalog, about a minute:
oc -n openshift-marketplace get catalogsource olympus-operators \ -o jsonpath='{.status.connectionState.lastObservedState}{"\n"}'# READY
oc get packagemanifest | grep olympus# olympus-operator Olympusx AI 21sThe Olympusx AI tile then appears in Ecosystem › Software Catalog. The package underneath it is olympus-operator.
Step 3: Give the operator its pull secret
Section titled “Step 3: Give the operator its pull secret”The operator runs as the ServiceAccount olympus-operator-controller-manager, which the install creates at the same moment as the pod that needs it. The first operator pod fails its pull; that is expected. Wait for the account, link the Secret to it, and replace the pod:
oc -n openshift-operators get serviceaccount olympus-operator-controller-manager
oc -n openshift-operators patch serviceaccount olympus-operator-controller-manager \ -p '{"imagePullSecrets":[{"name":"<pull-secret>"}]}'
oc -n openshift-operators delete pod \ -l app.kubernetes.io/name=olympus-operator,control-plane=controller-managerThe delete is not optional. A pod keeps the pull secrets it was created with, so linking the account does nothing for a pod that already exists. Do not rely on the cluster-wide pull secret for a private repository.
Wait for the operator, about a minute:
oc -n openshift-operators get csv olympus-operator.v<version> \ -o jsonpath='{.status.phase}{"\n"}'# SucceededEcosystem › Installed Operators shows Olympusx AI with the status Succeeded. A cluster that only serves models for an Olympusx AI running elsewhere stops here.
Step 4: Create the master key
Section titled “Step 4: Create the master key”The operator refuses to install without it:
oc -n olympus create secret generic olympus-master-key \ --from-literal=SECRETS_MASTER_KEY="$(openssl rand -base64 32)"The key name inside the Secret must be SECRETS_MASTER_KEY exactly. Store a copy now, with your other master keys:
oc -n olympus get secret olympus-master-key \ -o jsonpath='{.data.SECRETS_MASTER_KEY}' | base64 -dLosing it loses everything it sealed, including in a restored database.
Step 5: Store the relay password
Section titled “Step 5: Store the relay password”oc -n olympus create secret generic olympus-smtp \ --from-literal=password='<relay-password>'The resource names this Secret; the password never appears in the resource.
Step 6: Create the Olympus resource
Section titled “Step 6: Create the Olympus resource”Read the guardrails image digest the release pins:
oc -n openshift-operators get csv olympus-operator.v<version> \ -o jsonpath='{.spec.relatedImages[?(@.name=="olympus-guardrails")].image}{"\n"}'The output ends in @sha256:.... Use the sha256:... part, without the image name, as <guardrails-digest> below.
Save this as olympus.yaml:
apiVersion: olympus.olympusx.ai/v1kind: Olympusmetadata: name: olympus namespace: olympusspec: ingress: consoleHost: <console-host> gatewayHost: <gateway-host> auth: issuer: https://<console-host>/auth/realms/olympus secrets: masterKey: olympus-master-key registry: <pull-secret> database: mode: managed storageClass: <storage-class> walStorageClass: <storage-class> components: keycloak: true keycloakBootstrapUser: <admin-email> keycloakSmtp: host: <smtp-host> port: 587 encryption: starttls from: <sender-address> auth: username: <smtp-username> passwordSecret: olympus-smtp guardrails: true guardrailsImage: '<guardrails-digest>'| Field | What it does |
|---|---|
ingress.consoleHost, ingress.gatewayHost |
The two Routes. Sign-in is served on the console’s host under /auth |
auth.issuer |
With the built-in identity service it must be exactly https://<console-host>/auth/realms/olympus |
secrets.masterKey, secrets.registry |
The Secrets from steps 4 and 1 |
database.mode: managed |
Three PostgreSQL instances in this namespace, one primary |
database.storageClass, walStorageClass |
Where the data and write-ahead-log volumes come from |
The identity service line under components |
Deploys the built-in identity service, which signs people in |
components.keycloakBootstrapUser |
The first platform administrator. Created once, at first start |
components.keycloakSmtp |
The relay invitations go through. For port 465 set encryption: ssl; for a relay without login, leave out auth |
components.guardrails, guardrailsImage |
The guardrails service, pinned by digest. A bare digest, never a full image reference |
oc apply -f olympus.yamlIn the web console: Ecosystem › Installed Operators, project olympus, Olympusx AI, the Olympusx Platform tab, Create Olympusx AI, YAML view. Replace the example with your YAML, then Create.
A missing required field is refused at once, by name, for example spec.auth.issuer: Required value. Every other field, including backups and tenant isolation, is in Configuration and can be added to the running resource later with oc -n olympus edit olympuses.olympus.olympusx.ai olympus.
Guardrails start in observe mode. From the first request, every prompt and answer passes through the scanner, and every tenant starts in Observe: findings go to the audit trail and nothing is blocked or changed. A tenant administrator switches to enforcement in Guardrails. While the scanner is not ready, gateway requests are refused with guardrails_unavailable, in either mode.
Step 7: Watch it come up
Section titled “Step 7: Watch it come up”oc -n olympus get olympuses.olympus.olympusx.ai olympus -w# NAME VERSION COMPONENTS READY AGE# olympus 1.1.0 3/11 Unknown 20s# olympus 1.1.0 10/11 Unknown 4m# olympus 1.1.0 11/11 True 18mCOMPONENTScounts what serves: nine Deployments (the control plane, the gateway, the console, the metering and budget workers, the cache, the document converter, the identity service and the guardrails service), the object store and the database. Without the identity and guardrails services it ends at9/9.Unknownmeans still installing, not an error.Falsemeans the operator refused, and the reason names why (Troubleshooting).- Allow 15 to 30 minutes on a first install. The guardrails image is about 4.5 GB to download on each of the two nodes that run it.
Three warnings are expected on this resource, and none of them stops the install: no backup destination, tenant isolation off, and the model serving provider chosen for OpenShift.
oc -n olympus get events --field-selector reason=InstallWarningStep 8: Sign in
Section titled “Step 8: Sign in”oc -n olympus get routeThe console answers on <console-host>, the gateway on <gateway-host>. Continue with First sign-in, then Verify the installation.
What the operator does for OpenShift
Section titled “What the operator does for OpenShift”The operator asks the cluster whether it serves Routes and, when it does:
| Effect | |
|---|---|
| Routes, not Ingress | Renders two Routes with edge TLS. ingress.className and ingress.tlsSecret are reported as ignored |
| No pinned user IDs | Removes the fixed user and group IDs that restricted-v2 rejects. No SecurityContextConstraints object of your own is needed: the pods run without root, privilege escalation or capabilities, on a read-only root filesystem |
| Model serving | Each model runs as its own Deployment and Service on a registered cluster |
| NetworkPolicy peers | Admits OpenShift’s monitoring namespaces to the metrics ports, and openshift-operators to the database’s management port |
Monitoring (components.monitoring) needs user-workload monitoring turned on by a cluster administrator.
Install with Helm instead
Section titled “Install with Helm instead”On OpenShift 4.14 to 4.19, or when you need a chart value the resource does not expose, install with the Helm chart and its OpenShift values. Do not run both paths against one namespace.
-
Create the project, the pull secret and the Secrets as in Install on Kubernetes, with
ocin place ofkubectl:oc new-project olympus -
Write
olympus-values.yamlas on that page, without theingressblock, and with the console host for the Route:route:consoleHost: <console-host> # requiredgatewayHost: <gateway-host> # optional: OpenShift generates one when emptyroute.consoleHostis required, and the chart refuses to render without it: every token’s issuer is built from it. -
Pull the chart, which carries
values-openshift.yaml, and install with that file first and yours second:helm pull oci://<registry>/charts/olympus --version <version> --untar -d ./charthelm install olympus ./chart/olympus -n olympus \-f ./chart/olympus/values-openshift.yaml \-f olympus-values.yaml --wait --timeout 20m
values-openshift.yaml turns Routes on and Ingress off, removes the pinned user IDs, selects the managed database with three instances, turns monitoring on, and leaves the backup destination empty on purpose: the install stops with a message naming postgresqlCNPG.backup.destinationPath until you set it. For a first smoke test with no point-in-time recovery, add --set postgresqlCNPG.backup.enabled=false so the choice is on record in your shell history.
Keep the same file order on every upgrade. Reversed, an upgrade reverts to Ingress and pinned user IDs.