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.”
Two things that bite before you begin
Section titled “Two things that bite before you begin”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: autoCombined with disabling the root volumePermissions init container, this deploys
under the default project with no elevated SCC needed.
oc get pods -n my-postgresoc logs pg-postgresql-0 -n my-postgresoc rsh pg-postgresql-0 psql -U postgres -c '\l'Where the Helm chart stops being enough
Section titled “Where the Helm chart stops being enough”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.
The production route: CloudNativePG
Section titled “The production route: CloudNativePG”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/v1kind: Clustermetadata: name: pgspec: instances: 3 storage: size: 20Gi # backup + PITR configured declaratively to S3/MinIOThat gives you one primary and two hot standbys, automatic failover, and role-aware services — the operational gap the Helm chart leaves open.
The rule of thumb
Section titled “The rule of thumb”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.