Migrate from Bitnami to Operator-Managed PostgreSQL
This guide covers the manual steps required to migrate from the Bitnami chart-managed PostgreSQL installation (the default up to and including operator 25.1 releases) to the CloudNativePG (CNPG) operator-managed equivalent introduced in operator 25.3 releases.
The Bitnami PostgreSQL PVC and the CNPG Cluster PVC are incompatible on-disk formats. A manual dump-and-restore is required: dump the existing Bitnami data before upgrade, let the upgrade provision a fresh CNPG cluster, then restore the dump into it.
Before proceeding with any actions, ensure you have created a backup of your database.
Step 1. Retrieve credentials from the Bitnami PostgreSQL cluster.
POSTGRES_PASSWORD=$(kubectl get secret -n <NAMESPACE> dai-xlr-postgresql \
-o jsonpath="{.data.postgres-password}" | base64 -d)
echo "Postgres password: $POSTGRES_PASSWORD"
Step 2. Dump All Databases from the Bitnami Pod
Create a backup directory inside the running Bitnami pod and dump each database using the superuser account. The dumps use the custom format (-F c) which is compressed and supports selective restore.
The backup directory /bitnami/postgresql/backup lives on the same PVC as the data directory. Before creating it, verify there is sufficient free space: kubectl exec -n <NAMESPACE> dai-xlr-postgresql-0 -- df -h /bitnami/postgresql.
# Create the backup directory inside the pod
kubectl exec -n <NAMESPACE> dai-xlr-postgresql-0 -- mkdir -p /bitnami/postgresql/backup
# Dump xlr-db using the postgres superuser
kubectl exec -n <NAMESPACE> dai-xlr-postgresql-0 \
-- bash -c "PGPASSWORD='$POSTGRES_PASSWORD' pg_dump \
-U postgres -F c \
-f /bitnami/postgresql/backup/xlr-db.dump xlr-db"
# Dump xlr-report-db
kubectl exec -n <NAMESPACE> dai-xlr-postgresql-0 \
-- bash -c "PGPASSWORD='$POSTGRES_PASSWORD' pg_dump \
-U postgres -F c \
-f /bitnami/postgresql/backup/xlr-report-db.dump xlr-report-db"
# Verify the dump files exist and have non-zero size
kubectl exec -n <NAMESPACE> dai-xlr-postgresql-0 -- ls -lh /bitnami/postgresql/backup/
Step 3 — Copy Dumps to Local Machine
Copy the dumps out before the upgrade destroys the Bitnami pod and its PVC.
mkdir -p ./postgres-backup/release
kubectl cp -n <NAMESPACE> \
dai-xlr-postgresql-0:/bitnami/postgresql/backup/xlr-db.dump \
./postgres-backup/release/xlr-db.dump
kubectl cp -n <NAMESPACE> \
dai-xlr-postgresql-0:/bitnami/postgresql/backup/xlr-report-db.dump \
./postgres-backup/release/xlr-report-db.dump
ls -lh ./postgres-backup/release/
Step 4 — Scale Application to Zero Replicas
Scale the Release application pods to zero before running xl kube upgrade. This ensures no application writes occur during the migration and avoids connection errors while the PostgreSQL backend is being replaced.
# Record your current replicaCount before scaling down
REPLICA_COUNT=$(kubectl get digitalaireleases.xlr.digital.ai dai-xlr -n <NAMESPACE> \
-o jsonpath='{.spec.replicaCount}')
echo "Current replicaCount: $REPLICA_COUNT"
# Scale down to 0
kubectl patch -n <NAMESPACE> digitalaireleases.xlr.digital.ai dai-xlr \
--type=merge --patch '{"spec": {"replicaCount": 0}}'
# Wait until all Release pods are terminated
kubectl wait --for=delete pod -l app.kubernetes.io/instance=dai-xlr \
-n <NAMESPACE> --timeout=300s