Skip to content

Installing on OpenShift

Sovereign Home Cloud installs on OpenShift with the same chart and the same steps as Installing for Production. Three things differ:

  1. Every pod must run under the user ID range OpenShift assigns to the namespace.
  2. The bundled OpenSearch cannot run under such a user ID, so use your own OpenSearch.
  3. Hostnames are served by OpenShift Routes, which OpenShift creates from the chart's Ingress.

Security Context and User IDs

By default, every workload runs as the user and group IDs its image was built for. OpenShift assigns each namespace its own range of user IDs, and its default restricted-v2 security context constraint rejects any pod that asks for an ID outside that range. So on OpenShift, every workload's ID must move into the namespace's range.

Set the IDs in your values

  1. Create the namespace, then find the start of its range, the number before the slash:

    oc new-project home-cloud-control-plane
    oc get namespace home-cloud-control-plane \
      -o jsonpath='{.metadata.annotations.openshift\.io/sa\.scc\.uid-range}'
    # 1000730000/10000
    
  2. Add this to your values file, with your range start in place of <range start>:

    global:
      securityContext:
        fsGroup: <range start>
        runAsUser: <range start>
        runAsGroup: <range start>
    
    persistence-layer:
      postgresql:
        podSecurityContext: { fsGroup: <range start>, runAsUser: <range start>, runAsGroup: <range start> }
        containerSecurityContext: { runAsUser: <range start>, runAsGroup: <range start> }
      seaweedfs:
        podSecurityContext: { fsGroup: <range start>, runAsUser: <range start>, runAsGroup: <range start> }
        containerSecurityContext: { runAsUser: <range start>, runAsGroup: <range start> }
    
    solace-cloud-ca:
      k8s:
        securityContext:
          fsGroup: "<range start>"      # quoted
          runAsUser: "<range start>"    # quoted
    

global.securityContext moves most workloads. PostgreSQL, the object store and the datacenter agent come from included charts that cannot read it, so they are set separately to the same value. The chart refuses to install if any of them still has its image's ID.

Warning! Write the datacenter agent's two values as quoted strings, such as "1000730000". If they are unquoted, they are rendered in a form Kubernetes rejects; the chart refuses such values.

A namespace keeps its range for as long as it exists. If you delete and recreate the namespace, it can get a different range, and the values must be updated before you reinstall.

Routes

OpenShift serves the chart's Ingress through its router, creating one Route per hostname. Leave ingress.className blank to use the router, which is the cluster's default IngressClass.

Every entry in ingress.tls must have a secretName. Without one, OpenShift creates no Route and the hostname leads nowhere. You cannot fall back to the router's default wildcard certificate through the chart.

ingress:
  enabled: true
  className: ""
  consoleHost: console.apps.example.com
  opsHost: ops.apps.example.com
  tls:
    - secretName: home-cloud-control-plane-tls
      hosts: [console.apps.example.com, ops.apps.example.com]

Data Stores on OpenShift

Data store On OpenShift
PostgreSQL, Valkey, object store Bundled works under the namespace's user IDs
OpenSearch Use your own. The bundled OpenSearch image can only run as its own user ID, 1000, which the default constraints reject.

Configure your own OpenSearch as in Installing for Production:

dataLayer:
  opensearch:
    enabled: false
  external:
    opensearchHost: search.example.internal
    opensearchPort: 443
    opensearchProtocol: https

If you need the bundled OpenSearch

Allow the namespace's default service account, which the OpenSearch pod uses, to run as a fixed non-root user:

oc create rolebinding allow-nonroot-default \
  --clusterrole=system:openshift:scc:nonroot-v2 \
  --serviceaccount=home-cloud-control-plane:default \
  -n home-cloud-control-plane

Warning! This relaxes a security control. The binding lets every workload using the default service account in this namespace request a fixed non-root user ID, not only OpenSearch. It never permits root. It is a manual step per namespace, and must be repeated whenever the namespace is recreated.

No values change goes with it: the bundled OpenSearch already asks for its own user ID.

Next Steps