Skip to content

PostgreSQL on OpenShift — Helm, gotchas, and the production route

Running PostgreSQL on OpenShift is mostly a story about getting the security context right, plus a recent supply-chain wrinkle you have to handle before you start. Here’s the honest path from “quick dev instance” to “something you’d run in production.”

Watch on YouTube ↗

The Bitnami image move (August 2025). Bitnami migrated its free public images out of docker.io/bitnami into docker.io/bitnamilegacy, and those legacy images receive no further updates, security patches, or support. The chart is still Apache-2 and works, but a fresh install may try to pull a tag that no longer exists at the old path. You either point the chart at bitnamilegacy, mirror the image into your own registry, or move to a maintained alternative for anything long-lived.

OpenShift SCCs. By default OpenShift runs pods under restricted-v2, which assigns a random high UID from the namespace range and sets fsGroup to a namespace value. Older Bitnami charts hardcode runAsUser: 1001 and run a root init container to chmod the data volume — both of which restricted-v2 rejects. So the pod won’t schedule, or the init container crashes.

Making the chart behave under restricted-v2

Section titled “Making the chart behave under restricted-v2”

The clean approach is to let OpenShift inject the UID rather than fighting it. Recent Bitnami charts expose a flag for exactly this:

global:
compatibility:
openshift:
adaptSecurityContext: auto

Combined with disabling the root volumePermissions init container, this deploys under the default project with no elevated SCC needed.

Terminal window
oc get pods -n my-postgres
oc logs pg-postgresql-0 -n my-postgres
oc rsh pg-postgresql-0 psql -U postgres -c '\l'

The Bitnami chart gives you a deployment, not a managed database. By default it’s a single-replica StatefulSet with no replication, no leader election, no automatic failover. Real HA needs the separate postgresql-ha chart, which bolts on Patroni, Pgpool and etcd — a distributed system each team then owns. Day-2 operations (failover, minor-version upgrades, backup, point-in-time recovery) are all manual. For a throwaway dev or CI instance that lives for hours, that’s fine. For anything with a lifespan or a recovery requirement, it’s a liability.

CloudNativePG (CNPG) is a Kubernetes-native operator that owns the full PostgreSQL lifecycle. It’s a CNCF project with a Red Hat–certified build (provided and supported by EDB, installable from OperatorHub), and — the detail that matters here — it runs cleanly under restricted-v2 with no security-context workarounds at all.

Concern Bitnami Helm chart CloudNativePG
High availability Separate -ha chart (Patroni/Pgpool/etcd) Native primary + hot standbys
Automatic failover None Promotes furthest-ahead standby, repoints service
Rolling upgrades Manual, risky Standbys first, controlled switchover
Backups / PITR Roll your own Declarative WAL archiving to object store
Read/write endpoints Single service -rw / -ro / -r services follow the primary
OpenShift SCC Hardcoded UID + root init container Clean under restricted-v2
Image supply chain Frozen bitnamilegacy path Maintained community/EDB images
GitOps fit Values → static manifests Desired-state CRD, whole lifecycle in Git

A minimal CNPG cluster is a single declarative resource:

apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: pg
spec:
instances: 3
storage:
size: 20Gi
# backup + PITR configured declaratively to S3/MinIO

That gives you one primary and two hot standbys, automatic failover, and role-aware services — the operational gap the Helm chart leaves open.

Bitnami chart for genuinely disposable dev/CI. CloudNativePG (or Crunchy Postgres for Kubernetes) for anything you’d be sad to lose. The deciding question is never “which is easier to install” — it’s “who runs failover and restore at 3am,” and the operator answers that for you.