Database
PostgreSQL 14 or later. The only durable store in the system.
Three ways to connect
Cloud SQL Auth Proxy, on GKE. Best option where available. The sidecar authenticates with the pod's Workload Identity and connects with IAM database auth, so no password exists anywhere.
cloudSqlProxy:
enabled: true
instanceConnectionName: <PROJECT>:<REGION>:presponsieve-pg
iamUser: presponsieve@<PROJECT>.iam
dbName: presponsieve
This takes precedence over postgresql.* and externalDatabase.url. It requires Kubernetes 1.29 or later, because the proxy runs as a native sidecar. The sidecar is added to both the app Deployment and the migration Job, so migrations can reach the database too.
The IAM user is the service account email with .gserviceaccount.com stripped. The chart URL-encodes the @ for you.
A DSN in the secret. Put DATABASE_URL in the application secret. Preferred everywhere the proxy is unavailable.
postgresql+psycopg2://presponsieve:PASS@db.internal:5432/presponsieve
A DSN in values. externalDatabase.url. Works, and writes the database password into your values file and Git history. Evaluation only.
Preparing the database
The migration Job creates the schema, not the database or the role.
CREATE ROLE presponsieve WITH LOGIN PASSWORD '...';
CREATE DATABASE presponsieve OWNER presponsieve;
The role does not need superuser. It does need CREATE on the database, because alembic creates tables and indexes.
In-cluster Postgres
postgresql.enabled: true does not install PostgreSQL. It wires the app to a service named <release>-postgresql, which you install separately, typically the Bitnami chart with a matching release name.
That is worth restating because the flag name suggests otherwise.
Migrations
migration.enabled: true runs alembic upgrade head as a pre-install and pre-upgrade Helm hook. An unreachable database then fails the install cleanly, before any pod starts against a schema that is not there.
Leave it on. If you run migrations through your own pipeline instead, turn it off deliberately and make sure something else runs them.
Connections
Each replica holds a connection pool. Five replicas against a Postgres default of 100 connections is comfortable; if you scale well beyond that, either raise max_connections or put PgBouncer in front in transaction pooling mode.
Backups
The chart does not manage backups. Use your provider's, and test a restore. See Backup and restore.