Loading…
Loading…
Install the platform on Red Hat OpenShift Container Platform (OCP) using the standard Helm chart, native Routes, and the default restricted-v2 SCC.
This document provides instructions for installing the platform on Red Hat OpenShift Container Platform (OCP) using the standard Helm chart. It is a companion to the general Kubernetes / OpenShift (Helm) installation guide.
This guide focuses on the two primary differences when deploying to OpenShift:
Route resources for external access instead of standard Kubernetes Ingress.restricted-v2 Security Context Constraint (SCC) without requiring custom SCCs or privileged anyuid permissions.The platform's Helm chart is designed to work with restricted-v2 out of the box. All container images run as non-root users and listen on non-privileged ports (e.g., 8080), satisfying the SCC's requirements.
IMPORTANT
Read the main Kubernetes / OpenShift (Helm) guide first. It covers the chart's overall structure, image referencing, and requirements for databases and secrets. This page only details the OpenShift-specific configuration.
OpenShift uses Security Context Constraints (SCCs) to control pod permissions. By default, pods in a standard project are subject to the restricted-v2 SCC, which enforces several security policies. The platform's Helm chart is pre-configured to comply with these policies.
The restricted-v2 SCC requires that workloads:
runAsNonRoot: true).1000700000/10000).allowPrivilegeEscalation: false).RuntimeDefault seccomp profile.The Helm chart's default securityContext values satisfy all these conditions. The application services (admin-api, admin-ui, runtime, worker, s2r-discovery-ingest) listen on the non-privileged container port 8080.
To ensure compliance, you must leave the securityContext.runAsUser, runAsGroup, and fsGroup values as null in your configuration. This allows the OpenShift admission controller to inject the correct UID and GID from the project's allocated range. The chart defaults are already null.
The Helm chart supports both OpenShift Route and standard Kubernetes Ingress resources for exposing services. You must enable exactly one. Enabling both will cause the Helm installation to fail.
On OpenShift, using a Route is the most direct method, as it utilizes the built-in OpenShift Router (based on HAProxy).
flowchart TD
subgraph "Helm Chart Configuration"
A[Set `route.enabled: true`] --> B{OpenShift Route};
C[Set `ingress.enabled: true`] --> D{Kubernetes Ingress};
end
subgraph "API Consumer Request"
E[API Consumer] --> F[Edge Endpoint];
end
subgraph "OpenShift Cluster"
B --> G[OpenShift Router];
D --> H[Ingress Controller];
G --> I[Platform Services];
H --> I;
end
F -- DNS --> B;
F -- DNS --> D;| Feature | OpenShift Route (route.enabled: true) | Kubernetes Ingress (ingress.enabled: true) |
|---|---|---|
| Edge Component | OpenShift's built-in router (HAProxy). No extra installation needed. | Requires an Ingress controller (e.g., NGINX, Traefik) that you must install and manage. |
| TLS Termination | Supports edge, reencrypt, and passthrough termination policies. | Managed via a TLS secret or an integration like cert-manager. |
| Best For | Standard OpenShift deployments. | Vanilla Kubernetes, or OpenShift clusters where an Ingress controller is already established. |
If you already operate a preferred Ingress controller on your OCP cluster, you may use it by setting ingress.enabled: true and route.enabled: false.
oc CLI: Logged into your OCP cluster.helm CLI.Secret resources containing the database password and the platform's credential key. See the Configuration reference.Create a new project for the platform deployment. This command also allocates the UID/GID range that the restricted-v2 SCC will use for your pods.
oc new-project s2r
You can confirm the allocated UID range, but you do not need to use this value in your configuration.
oc get project s2r -o jsonpath='{.metadata.annotations.openshift\.io/sa\.scc\.uid-range}{"\n"}'
# Example output: 1000700000/10000
Container images are pulled from a private registry provided by Specaria. Create a docker-registry secret in your project with the credentials issued from the Specaria portal (portal.specaria.io).
oc create secret docker-registry s2r-registry \
--docker-server=<registry-from-portal> \
--docker-username='<robot-account-from-portal>' \
--docker-password='<robot-token-from-portal>' \
--docker-email='ops@example.com' \
--namespace s2r
Then, reference this secret in your Helm values file.
imagePullSecret:
create: false
imagePullSecrets:
- s2r-registry
Alternatively, the chart can create the secret for you if you provide the credentials directly in your values file. See the main Helm guide for details.
Create a values.yaml file to configure the Helm release. The following example demonstrates a typical OpenShift configuration using a Route for path-based routing.
openshift-values.yaml# Image source configuration.
global:
image:
registry: registry.example.com/specaria # No trailing slash
tag: "1.5.8"
pullPolicy: IfNotPresent
# Reference the pre-created pull secret.
imagePullSecret: { create: false }
imagePullSecrets: [ s2r-registry ]
# Database connection details using existing secrets.
database:
urlSecretName: s2r-db
urlSecretKey: url
passwordSecretName: s2r-db
passwordSecretKey: password
# OCP restricted-v2 compatible security context. These are the chart defaults.
securityContext:
enabled: true
runAsNonRoot: true
runAsUser: null
runAsGroup: null
fsGroup: null
# Disable Ingress and enable OpenShift Route.
ingress:
enabled: false
route:
enabled: true
host: s2r.apps.<cluster-domain> # Path-based routing under a single host
tls:
termination: edge
insecureEdgeTerminationPolicy: Redirect
paths:
admin-ui: /
admin-api: /admin
runtime: /runtime
# Optional: Configure autoscaling and pod disruption budgets for high availability.
autoscaling:
enabled: true
targetCPUUtilizationPercentage: 70
podDisruptionBudget:
enabled: true
minAvailable: 1
Install the chart using Helm.
helm install s2r ./s2r-chart \
--namespace s2r \
--values openshift-values.yaml
NOTE
If you received the chart as an OCI artifact, use the oci:// protocol with the registry reference provided by the Specaria portal:
helm install s2r oci://<specaria-registry>/s2r --version <chart-version> ...
After the Helm installation completes, verify that all components are running correctly.
Check deployment status:
for d in admin-api admin-ui runtime worker s2r-discovery-ingest; do
oc -n s2r rollout status deployment/$d
done
Confirm pods are running with an assigned UID:
# List all pods in the project
oc -n s2r get pods
# Check the runAsUser for each pod (should be a large, non-zero number)
oc -n s2r get pod -l app.kubernetes.io/name=s2r \
-o jsonpath='{range .items[*]}{.metadata.name}{" uid="}{.spec.securityContext.runAsUser}{"\n"}{end}'
Check the Route status:
oc -n s2r get routes
The output should show the host you configured, which is now admitted by the OpenShift Router.
Once all pods are ready and the route is admitted, browse to the configured host (e.g., https://s2r.apps.<cluster-domain>/) to access the Admin UI. The first user to authenticate via your configured OIDC provider becomes the bootstrap administrator.
You can validate your configuration before applying it to the cluster.
# Lint the chart with your values
helm lint ./s2r-chart --values openshift-values.yaml
# Render the Kubernetes manifests to inspect them locally
helm template s2r ./s2r-chart --values openshift-values.yaml
# Perform a server-side dry run against the OpenShift API server
helm install s2r ./s2r-chart --dry-run --namespace s2r --values openshift-values.yaml
This section details the OpenShift-specific configuration values for the Helm chart.
route)These values configure the OpenShift Route resource. They are only active when route.enabled: true.
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
enabled | boolean | false | Yes | Set to true to create Route resources. Mutually exclusive with ingress.enabled. |
host | string | — | No | A single hostname for path-based routing. Use with route.paths. |
paths | object | — | No | A map of service names to URL paths for path-based routing (e.g., admin-api: /admin). |
perServiceHosts | object | — | No | A map of service names to unique hostnames for host-based routing. Required for passthrough TLS. |
annotations | object | {} | No | A map of annotations to add to the Route resource. |
tls | object | {} | No | TLS configuration for the Route. See table below. |
route.tls)| Name | Type | Default | Required | Description |
|---|---|---|---|---|
termination | string | edge | No | TLS termination policy. One of edge, reencrypt, or passthrough. |
insecureEdgeTerminationPolicy | string | Redirect | No | Behavior for plain HTTP requests. One of None, Allow, or Redirect. |
key | string | — | No | PEM-encoded private key for the certificate. |
certificate | string | — | No | PEM-encoded public certificate. |
caCertificate | string | — | No | PEM-encoded CA certificate for the chain. |
destinationCACertificate | string | — | No | For reencrypt, the CA cert to verify the pod's serving certificate. |
The chart supports two routing strategies for Route resources.
route.host and route.paths.route.perServiceHosts. This is required for passthrough TLS termination.Example for host-based routing:
route:
enabled: true
perServiceHosts:
admin-ui: app.apps.<cluster-domain>
admin-api: api.apps.<cluster-domain>
runtime: runtime.apps.<cluster-domain>
tls:
termination: edge
You can configure TLS for your Route in several ways:
termination: edge and no custom certificate provided, the OpenShift Router will serve its default wildcard certificate (e.g., for *.apps.<cluster-domain>). This is the simplest option.reencrypt termination, you can annotate the platform's Service resources to have OpenShift automatically mint internal serving certificates.Secret and reference it in the Route via annotations.route.tls.key, route.tls.certificate, and route.tls.caCertificate.WARNING
You should not need a custom SCC or an anyuid service account binding. The chart is designed to run unprivileged. Granting anyuid permissions weakens your cluster's security posture and should be avoided.
| Symptom | Cause | Fix |
|---|---|---|
Pod is stuck in CreateContainerConfigError. Events show "unable to validate against any security context constraint … runAsUser: Invalid value". | A specific runAsUser was set in the Helm values, which conflicts with the project's dynamically assigned UID range. | Set securityContext.runAsUser, runAsGroup, and fsGroup to null (the chart default). This allows OpenShift to assign a valid UID from the project's range. |
| Pod fails admission with errors like "capabilities … not allowed" or "privilege escalation … not allowed". | The default security context settings were overridden with less restrictive values. | Ensure securityContext.allowPrivilegeEscalation is false and securityContext.capabilities.drop is [ALL]. These are the chart defaults. |
| Pod fails admission with a "seccompProfile" error. | The seccomp profile was changed from the required default. | Ensure securityContext.seccompProfile.type is set to RuntimeDefault. This is the chart default. |
The Route is created but returns a 503 Service Unavailable error. | The backing service has no ready pods, or you have enabled both route.enabled and ingress.enabled. | Check pod status with oc -n s2r get pods. Check service endpoints with oc -n s2r get endpoints. Ensure that only one of route.enabled or ingress.enabled is true. |
| Helm installation fails with "passthrough cannot be combined with path-based routing". | route.tls.termination is set to passthrough while using path-based routing (route.host and route.paths). | Passthrough TLS requires a dedicated host per service. Switch to host-based routing by configuring route.perServiceHosts instead. |
Pods are stuck in ImagePullBackOff. | The image pull secret is missing, incorrect, or not linked to the service account. | Verify the secret was created correctly with oc create secret docker-registry. Ensure it is referenced in your Helm values under imagePullSecrets. |