External database endpoint
Skip the in-cluster Bitnami PostgreSQL sub-chart and point OpenBox at your own managed database.
When to use external DB
- Prod: strongly recommended — managed DB is more reliable than in-cluster
- Compliance: your data must live in a specific service (RDS with existing SOC2 audit)
- Sharing: reuse an existing DB cluster with backup, monitoring, HA already configured
Step 1 — Disable in-cluster PG
postgresql:
enabled: false
This turns off the Bitnami sub-chart entirely — no PVCs, no pods, no Services.
Step 2 — Provide DB endpoint + credentials
Each sub-chart that touches DB has its own connection block. Wire them all:
openbox-backend:
db:
host: prod-openbox.abc123.us-east-1.rds.amazonaws.com
port: 5432
name: openbox
userSecretRef: openbox-backend-db-credentials # K8s Secret with username+password keys
sslMode: require # verify-ca / verify-full for stricter mtls
identity-service:
db:
host: prod-openbox.abc123.us-east-1.rds.amazonaws.com
port: 5432
name: keycloak
userSecretRef: keycloak-db-credentials
# openbox-core stores workflow state — if using self-hosted Temporal, needs a DB too
openbox-core:
temporal:
mode: self-hosted
server:
db:
host: prod-openbox.abc123.us-east-1.rds.amazonaws.com
port: 5432
name: temporal
userSecretRef: temporal-db-credentials
Step 3 — Pre-create databases + users
The chart does NOT auto-provision DBs. Create them ahead of helm install:
-- Connect as superuser
CREATE DATABASE openbox;
CREATE DATABASE keycloak;
CREATE DATABASE temporal; -- only if self-hosted Temporal
CREATE USER openbox WITH PASSWORD '<strong-password>';
CREATE USER keycloak WITH PASSWORD '<strong-password>';
CREATE USER temporal WITH PASSWORD '<strong-password>';
GRANT ALL PRIVILEGES ON DATABASE openbox TO openbox;
GRANT ALL PRIVILEGES ON DATABASE keycloak TO keycloak;
GRANT ALL PRIVILEGES ON DATABASE temporal TO temporal;
-- Postgres 15+: also grant on public schema
\c openbox
GRANT ALL ON SCHEMA public TO openbox;
\c keycloak
GRANT ALL ON SCHEMA public TO keycloak;
\c temporal
GRANT ALL ON SCHEMA public TO temporal;
Step 4 — Create K8s Secrets holding credentials
kubectl create secret generic openbox-backend-db-credentials \
--from-literal=username=openbox \
--from-literal=password='<pw>' \
-n openbox
kubectl create secret generic keycloak-db-credentials \
--from-literal=username=keycloak \
--from-literal=password='<pw>' \
-n openbox
(Or use External Secrets Operator — see Secrets and ConfigMaps.)
Step 5 — Network reachability
- AWS RDS — RDS security group must allow ingress from EKS node security group on port 5432
- Cloud SQL — Cloud SQL Auth Proxy sidecar OR Private IP + VPC peering
- Azure Database — VNet peering OR firewall rule allowing AKS subnet range
Verify from a pod:
kubectl run -it --rm --image=postgres:16-alpine dbtest -n openbox -- \
psql -h <endpoint> -U openbox -d openbox -c 'SELECT version();'
Step 6 — Migration on helm install
The chart runs a schema migration Job on first install (helm.sh/hook: pre-install,pre-upgrade). Confirm it succeeds:
kubectl get jobs -n openbox
kubectl logs job/openbox-backend-migrate -n openbox
If migration fails, helm install --atomic rolls back. Investigate connection / permission issues before retry.
Multi-DB single-instance layout
You can use ONE Postgres instance with multiple databases (openbox / keycloak / temporal). Cheaper for small deploys but couples upgrade / backup schedules. Use separate instances for enterprise / prod-HA.
Verify post-install
kubectl exec -it deploy/openbox-backend -n openbox -- \
sh -c 'echo "SELECT 1;" | psql "$DATABASE_URL"'
# Should return "1" — connection + credentials work
If pod can't connect: check kubectl describe pod for env var wiring, then check RDS/DB security group.