Configure static PV binding

Bind Red Hat Edge Manager PersistentVolumeClaims (PVCs) to pre-provisioned PersistentVolumes (PVs) during installation to control which PVs the database and Alertmanager use. Use this approach on clusters without dynamic storage provisioning or when you need explicit PV assignment.

Before you begin

  • A Red Hat OpenShift Container Platform cluster where you want to bind Red Hat Edge Manager PVCs to specific pre-provisioned PVs, either because the cluster has no dynamic storage provisioner or because you want explicit control over PV selection.
  • Pre-provisioned PersistentVolumes with sufficient capacity: at least the configured db.builtin.storage.size (default 60 GiB) for the PostgreSQL database PV and minimum 2 GiB for the Alertmanager PV.
  • PVs for the PostgreSQL database use a storage backend other than NFS. NFS does not support chown operations required by the PostgreSQL container startup process to set data directory ownership via the pod fsGroup security context.
  • PVs support ReadWriteOnce access mode.
  • Cluster administrator permissions.
  • The Helm CLI is installed (for disconnected installation) or you have access to the Red Hat OpenShift Container Platform Software Catalog (for connected installation).

About this task

Red Hat Edge Manager creates two PVCs during installation:

  • A PVC for the built-in PostgreSQL database, which requires at least the configured db.builtin.storage.size (default 60 GiB).
  • A PVC for the Alertmanager, which requires a minimum of 2 GiB.

On clusters without a dynamic StorageClass, you must pre-provision PVs and configure the Helm chart to bind PVCs to those PVs. You can use one of two binding approaches:

Name-based binding (volumeName)
Binds the PVC directly to a PV by its resource name. Use this approach when you know the exact PV name and want a deterministic one-to-one binding.
Label-based binding (selector.matchLabels)
Binds the PVC to any PV that carries matching labels. Use this approach when you manage PVs through labeling conventions or want flexibility in PV selection.

If you set both volumeName and selector.matchLabels for the same component, the Helm chart renders both fields on the PVC. Kubernetes then requires the PVC to match a PV that satisfies both the name and the label selector.

Procedure

  1. Verify that the cluster does not have a dynamic StorageClass for the target storage:
    $ oc get storageclass

    If no StorageClass is listed, or if the listed StorageClass does not have an active provisioner, proceed with static PV binding.

  2. Create PersistentVolumes on the cluster with adequate capacity and access modes.

    The following example creates a PV for the PostgreSQL database. Replace <pv_name> with the name of the PV and <storage_path> with the path to the storage on the node:

    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: <pv_name>
      labels:
        app: rhem-database
    spec:
      capacity:
        storage: 60Gi
      accessModes:
        - ReadWriteOnce
      persistentVolumeReclaimPolicy: Retain
      storageClassName: ""
      hostPath:
        path: <storage_path>

    The Red Hat Edge Manager Helm chart automatically sets storageClassName: "" on the PVC when volumeName or selector.matchLabels is configured and global.storageClassName is left unset — this prevents the default StorageClass admission controller from injecting a mismatched class into the PVC. Setting storageClassName: "" on the PV here ensures its storage class value matches the PVC, which Kubernetes requires for binding.

    The following example creates a PV for Alertmanager. Replace <alertmanager_pv_name> with the name of the PV and <alertmanager_storage_path> with the path to the storage on the node:

    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: <alertmanager_pv_name>
      labels:
        app: rhem-alertmanager
    spec:
      capacity:
        storage: 2Gi
      accessModes:
        - ReadWriteOnce
      persistentVolumeReclaimPolicy: Retain
      storageClassName: ""
      hostPath:
        path: <alertmanager_storage_path>
    Note

    The hostPath volume type is shown for illustration. In production, use local volumes, block storage, or another non-NFS backend appropriate for your environment.

  3. Apply the PV definitions to the cluster:
    $ oc apply -f <pv_definition_file>.yaml
  4. If you use label-based binding, verify that the PVs have the labels you intend to select on:
    $ oc get pv --show-labels
  5. Prepare the Helm values for PVC-to-PV binding.

    Choose one of the following approaches:

    Option A — Name-based binding

    Set db.builtin.volumeName and alertmanager.volumeName to the names of the PVs you created. Replace <pv_name> and <alertmanager_pv_name> with the actual PV names:

    db:
      builtin:
        volumeName: "<pv_name>"
    
    alertmanager:
      volumeName: "<alertmanager_pv_name>"

    Option B — Label-based binding

    Set db.builtin.selector.matchLabels and alertmanager.selector.matchLabels to match the labels on the PVs. The following example uses the labels applied in step 2:

    db:
      builtin:
        selector:
          matchLabels:
            app: rhem-database
    
    alertmanager:
      selector:
        matchLabels:
          app: rhem-alertmanager
  6. Optional: Set db.builtin.fsGroup to a numeric group ID if the pre-provisioned PV requires a specific group owner for the PostgreSQL data directory:
    db:
      builtin:
        fsGroup: "26"
  7. Leave global.storageClassName unset (default) unless your PVs are provisioned under a specific non-default StorageClass name — the chart prevents default-class injection automatically when volumeName or selector.matchLabels is set.

    If your PVs use a specific non-default StorageClass, set global.storageClassName to that class name:

    global:
      storageClassName: "<storage_class_name>"
  8. Include the static PV binding values when you install Red Hat Edge Manager.
    • For a disconnected Helm install, pass the values file to helm install:
      $ helm install flightctl ./redhat-rhem-<version>.tgz -n <namespace> \
        -f <static_pv_values_file>.yaml \
        --set global.auth.caCert="$(cat /tmp/ingress-ca.crt)"
    • For a Software Catalog install, paste the static PV binding values into the YAML editor in the Red Hat OpenShift Container Platform web console before you click Create.
    Warning

    For the database, volumeName and selector.matchLabels are immutable on an existing PersistentVolumeClaim — changing them causes helm upgrade to fail.

    For Alertmanager, these fields are part of the StatefulSet volumeClaimTemplates, which Kubernetes does not allow changing on an existing StatefulSet — helm upgrade fails with a Forbidden: updates to statefulset spec error regardless of what changed.

    To change the PV binding for either component after initial installation, set the values before the first helm install. Otherwise: delete the StatefulSet (Alertmanager) or the PVC (database), delete the associated PVC if it still exists, clear the target PV claimRef if reusing the same PV, then re-run helm upgrade.

  9. Verify that the PVCs are bound to the intended PVs:
    $ oc get pvc -n <namespace>

    The output shows each PVC with a STATUS of Bound and a VOLUME column that matches the intended PV name.

  10. Verify that the database and Alertmanager pods are running:
    $ oc get pods -n <namespace>

    The database pod and the Alertmanager pod show a STATUS of Running.

  11. Optional: Inspect the PVC-to-PV binding details for the database PVC:
    $ oc describe pvc <database_pvc_name> -n <namespace>