DevOps · K8s · Volleyball · Travel  •  DevOps · K8s · Volleyball · Travel  •  DevOps · K8s · Volleyball · Travel
Explore NY Stream

Fix PostgreSQL "Permission denied" on /var/lib/pgsql in OpenShift

— ny_wk

Fix PostgreSQL

You deploy PostgreSQL on OpenShift or Kubernetes and the pod dies instantly with:

mkdir: cannot create directory '/var/lib/pgsql/data/userdata': Permission denied

The database can't write to its own data directory. This is almost always a storage permissions problem between the container's user and the mounted volume — not a Postgres bug. Here's how to fix it.

Why it happens

Two common causes:

  • SELinux labels: on SELinux-enforcing hosts, the mounted volume directory isn't labeled for container access, so the kernel blocks the write.
  • UID/GID mismatch: OpenShift runs containers with a random, non-root user by default. If the volume is owned by root (or a fixed UID) and isn't group-writable for the pod's group, the Postgres process can't create its directory.

Fix 1 — Set the right SELinux label (host volumes)

If you're using a host-path/local volume on an SELinux host, relabel it so containers may use it:

chcon -Rt svirt_sandbox_file_t /path/to/volume

(Adjust the path and type to your environment.) This tells SELinux the directory is fair game for container processes.

Fix 2 — Fix ownership with fsGroup (the Kubernetes-native way)

Better than chasing host permissions: let the platform set group ownership of the volume to the pod's group using a securityContext:

  • Set securityContext.fsGroup on the pod so the mounted volume is group-owned by that GID and group-writable.
  • OpenShift's default restricted SCC assigns a random UID but a known fsGroup — aligning the volume's group with it lets the non-root Postgres user write.

Fix 3 — Use a supported PostgreSQL image / StorageClass

The Red Hat/OpenShift PostgreSQL images are built to run as an arbitrary non-root UID and handle these permissions correctly. Use the official image from the catalog, and a dynamic StorageClass (which provisions volumes with proper permissions) rather than a hand-mounted host path.

Key takeaways

  • The error is a volume permissions issue, not a Postgres fault.
  • On SELinux hosts, relabel host volumes: chcon -Rt svirt_sandbox_file_t /path.
  • The clean fix is securityContext.fsGroup so the volume is writable by the pod's group.
  • Prefer the official OpenShift Postgres image + a dynamic StorageClass to avoid this entirely.

Frequently asked questions

Why does it run as a random user?

OpenShift's restricted security context assigns an arbitrary non-root UID for safety, so images must not assume they run as a fixed user or root.

Should I just run the pod as root?

No — that defeats OpenShift's security model and often isn't allowed. Fix the volume permissions/fsGroup instead.

What does chcon do here?

It sets the SELinux type label on the directory so container processes are permitted to access it.

fsGroup or SELinux — which should I use?

For dynamically provisioned volumes, fsGroup is the right, portable fix. chcon is for host-path volumes on SELinux nodes.

Match the volume's permissions to the non-root user OpenShift gives you — via fsGroup (or the right SELinux label) — and PostgreSQL starts cleanly.