Loading…
Loading…
Install the platform on a Kubernetes or OpenShift cluster using the provided Helm chart. This guide covers prerequisites, configuration, and high
This document describes how to install the platform on a Kubernetes or OpenShift cluster using the provided Helm chart. The Helm chart, generally available since v1.0, deploys the platform as a set of cluster-managed workloads, enabling high availability, horizontal scaling, and operational consistency with other Kubernetes-native applications.
This installation method is suitable for API publishers who already operate a Kubernetes or OpenShift cluster and want to manage the platform's lifecycle (installation, upgrades, scaling) using standard Kubernetes tooling. It requires an external PostgreSQL database, which you manage independently of the application pods.
The chart deploys the following services: admin-api, admin-ui, runtime, worker, and s2r-discovery-ingest. It also orchestrates database schema migrations via a Helm Job that runs before application pods are updated, ensuring a safe upgrade process.
Before installing the Helm chart, ensure your environment meets the following requirements:
cert-manager or another method for provisioning TLS certificates for Ingress.s2r).Secret resources must be created in the target namespace:
The Helm chart defines and manages all the necessary Kubernetes resources to run the platform.
Deployment and a Service for each core component: admin-api, admin-ui, runtime, worker, and s2r-discovery-ingest.admin-api, admin-ui, runtime), the chart can create Ingress resources to expose them via a single host and path-based routing. The worker service is internal by default and only exposed via a ClusterIP service.Job that runs as a pre-install and pre-upgrade Helm hook. This job uses Flyway to apply necessary schema changes to the PostgreSQL database before any of the application Deployments are rolled out. This ensures that the application pods always start against a compatible database schema.The chart supports two methods for referencing container images:
values.yaml.global.image.registry and global.image.tag. The chart then composes the full image URL (e.g., <registry>/<repository>:<tag>) for each component. You can also override this globally or on a per-component basis.The Helm chart is designed to support highly available deployments:
runtime service is stateless and can be scaled horizontally by increasing its replica count to handle higher traffic loads.HorizontalPodAutoscaler resources for each component to automatically scale replicas based on CPU utilization.PodDisruptionBudget resources can be enabled to ensure a minimum number of replicas are available during voluntary disruptions, such as node maintenance.The single source of truth for all configuration and state is the external PostgreSQL database. Ensuring the database itself is highly available is critical for the overall availability of the platform.
The Helm chart is included in the release artifact bundle. The following examples assume you have extracted the bundle and are referencing the chart from a local path, ./s2r-chart.
my-values.yaml file with your specific configuration. See the example below for the structure.helm install command to deploy the chart into your cluster.helm install s2r ./s2r-chart \
--namespace s2r --create-namespace \
--values my-values.yaml
If you receive the chart as an OCI artifact, you can install it by reference:
helm install s2r oci://<your-registry>/s2r --version <chart-version> ...
The exact OCI reference is provided with the release artifact.
values.yamlThis example illustrates the structure and common keys for configuring the chart.
# Image scheme (only needed when NOT using the Release Controller).
global:
image:
registry: registry.example.com/specaria # no trailing slash
tag: "1.5.8" # defaults to releaseVersion when empty
pullPolicy: IfNotPresent
# Private registry pull secret. Either let the chart create one...
imagePullSecret:
create: true
name: s2r-registry
registry: registry.example.com
username: <robot-account>
password: <robot-token>
email: ops@example.com
# ...or reference a secret you created out of band:
# imagePullSecret: { create: false }
# imagePullSecrets: [ my-existing-pull-secret ]
# Database — the chart does NOT bundle Postgres. Point at your managed/in-VPC
# instance via existing Kubernetes Secrets.
database:
urlSecretName: s2r-db # Secret holding the JDBC/connection URL
urlSecretKey: url
passwordSecretName: s2r-db # Secret holding the DB password
passwordSecretKey: password
# Restricted security context (compatible with OpenShift restricted-v2 SCC).
# On vanilla Kubernetes, set a non-root UID. On OpenShift, leave runAsUser/
# fsGroup null so the SCC assigns them from the namespace range.
securityContext:
enabled: true
runAsNonRoot: true
runAsUser: 1000 # OpenShift: leave null
runAsGroup: 1000 # OpenShift: leave null
fsGroup: 1000 # OpenShift: leave null
# Resource tier per component: small | medium | large (or override `resources`).
components:
admin-api: { resourceTier: medium }
admin-ui: { resourceTier: small }
runtime: { resourceTier: large }
worker: { resourceTier: medium }
s2r-discovery-ingest: { resourceTier: small }
# Per-component autoscaling (min/max come from each component's `autoscale`).
autoscaling:
enabled: true
targetCPUUtilizationPercentage: 70
# Spread replicas across nodes for HA (only applied to multi-replica services).
podDisruptionBudget:
enabled: true
minAvailable: 1
# Ingress for the public-https services (runtime, admin-api, admin-ui).
ingress:
enabled: true
className: nginx
host: s2r.example.com # path-based routing under one host
tls:
enabled: true
# Either a pre-created TLS secret...
secretName: s2r-tls
# ...or cert-manager issuance:
# certManager: { clusterIssuer: letsencrypt }
# Path-based routes (default). For host-based routing instead, set perServiceHosts.
paths:
admin-ui: /
admin-api: /admin
runtime: /runtime
Before applying the chart to a cluster, you can validate your configuration:
# Static linting of the chart and values
helm lint ./s2r-chart --values my-values.yaml
# Render the Kubernetes manifests locally to inspect them
helm template s2r ./s2r-chart --values my-values.yaml
# Perform a server-side dry run against a live cluster API server
helm install s2r ./s2r-chart --dry-run --namespace s2r --values my-values.yaml
To apply changes or perform an initial install, use helm upgrade --install.
Run the Helm command:
helm upgrade --install s2r ./s2r-chart \
--namespace s2r --create-namespace \
--values my-values.yaml
Verify that all deployments have rolled out successfully:
kubectl -n s2r rollout status deployment/admin-api
kubectl -n s2r rollout status deployment/admin-ui
kubectl -n s2r rollout status deployment/runtime
kubectl -n s2r rollout status deployment/worker
kubectl -n s2r rollout status deployment/s2r-discovery-ingest
Once the rollout is complete, browse to the host configured in ingress.host (e.g., https://s2r.example.com/). You should be prompted to log in via your OIDC provider. The first authenticated user will become the bootstrap administrator.
The values below are illustrative of the chart's configuration shape. The values.yaml file and README included in your release artifact are the authoritative sources for exact key names and default values.
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
global.image.registry | string | — | No | The global container registry for all components. Required if not using the Release Controller. |
global.image.tag | string | releaseVersion | No | The global image tag for all components. Defaults to the chart's release version. |
global.image.pullPolicy | string | IfNotPresent | No | The global image pull policy. |
imagePullSecret.create | boolean | — | No | If true, the chart creates a new imagePullSecret. |
imagePullSecret.name | string | s2r-registry | No | Name of the imagePullSecret to create or use. |
imagePullSecret.registry | string | — | Yes, if create is true | The registry server address for the pull secret. |
imagePullSecret.username | string | — | Yes, if create is true | The username for registry authentication. |
imagePullSecret.password | string | — | Yes, if create is true | The password or token for registry authentication. |
imagePullSecret.email | string | — | Yes, if create is true | The email for registry authentication. |
imagePullSecrets | array | — | No | An array of existing imagePullSecret names to use for pulling images. Used when imagePullSecret.create is false. |
database.urlSecretName | string | — | Yes | The name of the Kubernetes Secret containing the database JDBC URL. |
database.urlSecretKey | string | url | No | The key within urlSecretName that holds the JDBC URL. |
database.passwordSecretName | string | — | Yes | The name of the Kubernetes Secret containing the database password. |
database.passwordSecretKey | string | password | No | The key within passwordSecretName that holds the password. |
securityContext.enabled | boolean | — | No | Enables the pod-level security context. |
securityContext.runAsNonRoot | boolean | true | No | Ensures pods run as a non-root user. |
securityContext.runAsUser | integer | 1000 | No | The UID to run the container as. On OpenShift, leave this null. |
securityContext.runAsGroup | integer | 1000 | No | The GID to run the container as. On OpenShift, leave this null. |
securityContext.fsGroup | integer | 1000 | No | The GID for the pod's filesystem. On OpenShift, leave this null. |
components.<name>.resourceTier | string | — | No | Sets a predefined resource request/limit tier (small, medium, large). |
autoscaling.enabled | boolean | — | No | If true, creates a HorizontalPodAutoscaler for each component. |
autoscaling.targetCPUUtilizationPercentage | integer | 70 | No | The target average CPU utilization for the HPA. |
podDisruptionBudget.enabled | boolean | — | No | If true, creates a PodDisruptionBudget for multi-replica services. |
podDisruptionBudget.minAvailable | integer | 1 | No | The minimum number of available pods during a voluntary disruption. |
ingress.enabled | boolean | — | No | If true, creates Ingress resources for public services. |
ingress.className | string | — | No | The ingressClassName for the Ingress resources. |
ingress.host | string | — | Yes, if enabled | The hostname for path-based routing to all public services. |
ingress.tls.enabled | boolean | — | No | Enables TLS on the Ingress. |
ingress.tls.secretName | string | — | No | Name of a pre-existing Kubernetes Secret containing the TLS certificate and key. |
ingress.tls.certManager.clusterIssuer | string | — | No | The name of a cert-manager ClusterIssuer to use for obtaining a TLS certificate. |
ingress.paths.<service> | string | — | No | The path for a specific service (e.g., admin-ui: /). |
The Helm chart is compatible with OpenShift. The default securityContext is configured to be compatible with the restricted-v2 Security Context Constraint (SCC).
When deploying to OpenShift, you must leave securityContext.runAsUser, runAsGroup, and fsGroup set to null in your values.yaml. This allows OpenShift to assign a UID from the namespace's allocated range. Specifying a hardcoded UID that falls outside this range will cause pod creation to fail.
For exposing services, you can use standard Kubernetes Ingress or OpenShift Route resources, which can be enabled via the chart's values.
If an upgrade fails, you can roll back to a previous revision using the helm rollback command.
helm rollback s2r <revision> -n s2r
If pods fail to start on OpenShift due to security context errors, verify that securityContext.runAsUser, runAsGroup, and fsGroup are all set to null in your values.yaml. This is required for compatibility with the restricted-v2 SCC.