Files
Mukul Sharma d4bb8985fb Add a hand-written PostgreSQL chart for toolshed
Not Bitnami's: that registry has been actively unstable here (it broke
Contour twice, infra issue #4) and PostgreSQL publishes no official chart.
A single StatefulSet, PVC and Service is small enough that owning it costs
less than depending on an unstable repackage.

Credentials come from an existing Secret rather than being generated by
the chart — a chart that generates its own password regenerates it on
every render and silently locks you out of the existing volume.

Details that matter and are easy to get wrong:
  - PGDATA is a subdirectory of the mount, not the mount itself. initdb
    refuses to run in a directory that already has contents.
  - Probes run through a shell. Kubernetes does not expand $(VAR) inside
    exec probe commands, only in command/args.
  - fsGroup 70 so the volume stays writable after the entrypoint drops
    from root to the postgres user on the Alpine variant.
  - shared_buffers cut to 32MB from PostgreSQL's 128MB default. The node
    has 8GB and was at its ceiling before this.

Verified with helm template.
2026-09-04 16:21:26 +05:30

49 lines
1.6 KiB
YAML

# PostgreSQL for toolshed's control plane.
#
# Deployed as shared infrastructure in its own namespace rather than inside
# the toolshed namespace, so it is addressed over cluster DNS like any other
# platform component and its lifecycle is independent of the application
# that happens to be its first consumer:
#
# postgresql.postgres.svc.cluster.local:5432
#
# Credentials come from Vault through External Secrets — see
# devops-infra-argo-config/secretstores/toolshed-postgres-credentials.yaml.
# The Secret must exist before this pod can start; a missing Secret leaves it
# in CreateContainerConfigError rather than failing in a way that explains
# itself.
fullnameOverride: postgresql
image:
repository: postgres
tag: "16-alpine"
pullPolicy: IfNotPresent
existingSecret: postgresql-credentials
database: toolshed
persistence:
enabled: true
# local-path-provisioner, this cluster's default StorageClass — installed
# right after Cilium precisely because kubeadm ships no default (unlike
# k3s). 5Gi is generous for control-plane metadata; the volume is not
# resizable in place with this provisioner, so it is sized up front.
storageClass: local-path
size: 5Gi
config:
# Deliberately far below PostgreSQL's 128MB default. The node has 8GB and
# was already at its ceiling before this; the demo apps were scaled to zero
# to make room. Revisit only if query performance actually suffers, which
# for a handful of control-plane tables it will not.
sharedBuffers: 32MB
maxConnections: "50"
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
memory: 256Mi