PostgreSQL Operator

A PostgreSQL Operator as an Alternative to a Hand-Rolled StatefulSet

BookNest's StatefulSet (StatefulSets and PostgreSQL) has no replica, failover or scheduled backup. CloudNativePG 171,411 (github.com/cloudnative-pg/cloudnative-pg (https://github.com/cloudnative-pg/cloudnative-pg 9,370 ), Apache-2.0, from EDB, CNCF Sandbox since January 2025) adds all three. It creates Pods, PVCs, Services <name>-rw (primary), -ro and -r, and a Secret <name>-app with the keys the chart's db.secret expects:

helm/booknest-db.yaml: a CloudNativePG cluster for BookNestYAML
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata: { name: booknest-db, namespace: booknest-helm }
spec:
  instances: 2                   # a primary and a streaming replica
  storage: { size: 1Gi, storageClass: booknest-data }
  bootstrap: { initdb: { database: booknest, owner: booknest } }
  smartShutdownTimeout: 10       # the default 180 s waits that long for clients to disconnect
Installing the operator, switching the release to it, then losing the primaryYAML
R=https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/release-1.30/releases
kubectl apply --server-side -f $R/cnpg-1.30.1.yaml >/dev/null
kubectl -n cnpg-system rollout status deployment/cnpg-controller-manager >/dev/null
k() { kubectl -n booknest-helm "$@"; }
k apply -f helm/booknest-db.yaml
k wait --for=condition=Ready cluster/booknest-db --timeout=10m >/dev/null
helm upgrade booknest helm/booknest -n booknest-helm --reuse-values --wait \
  --set postgres.enabled=false,db.host=booknest-db-rw,db.secret=booknest-db-app | grep REVISION
k delete pod booknest-db-1 --wait=false
S0=$(date +%s)
until k get cluster booknest-db | grep -q 'healthy.*db-2$'; do sleep 1; done
echo "new primary after $(( $(date +%s) - S0 )) s"; k get cluster booknest-db
helm test booknest -n booknest-helm --logs | grep books
git add k8s/promotion-crd.yaml helm/booknest-db.yaml
git commit -qm "Add a CRD and a CNPG cluster"
Output
cluster.postgresql.cnpg.io/booknest-db created
REVISION: 6
pod "booknest-db-1" deleted from booknest-helm namespace
new primary after 25 s
NAME          AGE   INSTANCES   READY   STATUS                     PRIMARY
booknest-db   88s   2           2       Cluster in healthy state   booknest-db-2
6 books through booknest-web

The API created its schema in the new database, the chart's StatefulSet disappeared, and failover needed no human. Backups and connection pooling are further CRDs of the same operator.