Upgrade the in-cluster PostgreSQL database from version 14 to version 16
Learn how to upgrade your in-cluster PostgreSQL database from version 14 to version 16 in Harness Self-Managed Enterprise Edition.
This guide explains how to upgrade the in-cluster PostgreSQL database in a Harness Self-Managed Enterprise Edition (SMP) deployment from PostgreSQL 14 to PostgreSQL 16 using pg_upgrade --link.
It also explains how to back up your data, validate the upgrade, and restore the database if necessary.
IMPORTANT
This guide and the included scripts apply only to the Harness-provided internal PostgreSQL deployed as part of the SMP Helm chart. If you use an external PostgreSQL database provided by a cloud provider (such as Amazon RDS, Google Cloud SQL, or Azure Database for PostgreSQL), refer to your cloud provider documentation for the PostgreSQL upgrade process.
Before you begin
kubectl access: Configured with access to the target namespace where PostgreSQL runs.
Helm upgrade: Run
helm upgradeto deploy thepg-upgrade-configConfigMap that provides the upgrade and PG16 images to the script.Backup: Back up the PostgreSQL data volume before starting the upgrade. For available backup methods, go to Backup and restore options.
Data verification
The pg-upgrade.sh script automatically captures a verification baseline before the upgrade and runs verification again after the upgrade completes. It then generates a comparison report showing row-count changes per table with a pass/fail status (within a 5% tolerance).
The verification captures:
Database sizes (
pg_database_size)Per-table row counts (
n_live_tupfrompg_stat_user_tables)
Verification output files are saved locally with timestamps:
pg-verify-before-<namespace>-<timestamp>.txtpg-verify-after-<namespace>-<timestamp>.txtpg-upgrade-report-<namespace>-<timestamp>.txt
Run the upgrade
The pg-upgrade.sh script performs the following actions:
Verifies the current PostgreSQL version (scales up the pod if necessary).
Captures pre-upgrade data verification baseline.
Prompts for backup confirmation.
Scales down the PostgreSQL StatefulSet.
Launches a temporary upgrade pod (
pg-upgrade-job) with both PG14 and PG16 binaries.Runs
pg_upgrade --check(dry run).Runs
pg_upgrade --linkto perform the upgrade by creating hard links instead of copying data files.Swaps data directories.
Patches the StatefulSet image to PG16.
Scales up the StatefulSet and runs
ANALYZE.Captures post-upgrade data verification and generates a comparison report.
Run the script
The upgrade and backup scripts are in the scripts directory of the Harness Helm chart. Run them from that directory:
Image configuration
The script reads image values from the pg-upgrade-config ConfigMap in the target namespace. This ConfigMap is created automatically during helm upgrade. It provides:
PG_NEW_IMAGE: the PG16 runtime image.UPGRADE_IMAGE: the image containing both PG14 and PG16 binaries.
You can override these values by setting the corresponding environment variables before running the script.
Environment variable overrides
PG_OLD_VERSION
14
Source PostgreSQL major version
PG_NEW_VERSION
16
Target PostgreSQL major version
PG_STS_NAME
postgres
StatefulSet name
PG_USER
postgres
PostgreSQL superuser name
PG_NEW_IMAGE
From pg-upgrade-config ConfigMap
PG16 runtime image
UPGRADE_IMAGE
From pg-upgrade-config ConfigMap
Image with both PG14 and PG16 binaries
PG_UPGRADE_JOBS
4
Parallel jobs for pg_upgrade
PG_OLD_BINDIR
/usr/lib/postgresql/14/bin
Path to PG14 binaries in upgrade image
PG_NEW_BINDIR
/usr/lib/postgresql/16/bin
Path to PG16 binaries in upgrade image
PG_DATADIR
/bitnami/postgresql/data
PostgreSQL data directory path
Interactive prompts
During execution, the script prompts you to confirm the following actions:
Backup confirmation
Scale-down confirmation
After
--checkpasses, before the actual upgrade
About link mode
pg_upgrade --link creates hard links to the existing data files instead of copying them into a new data directory. This significantly reduces upgrade time, especially for large databases. Because the upgraded data shares the original files, you cannot use the original data directory after the upgrade completes. Use the backup you created before the upgrade if you need to roll back.
Review the upgrade report
After the upgrade completes, the script generates a comparison report (pg-upgrade-report-<namespace>-<timestamp>.txt) that compares row counts before and after the upgrade.
Expected results:
PASS: Row counts match or differ by less than 5%.
SKIP: A table exists in the pre-upgrade capture but was not found in the post-upgrade capture (review manually).
FAIL: Row counts differ by more than 5% (investigate before restoring application traffic).
Small differences in batch or queue tables are expected due to application activity between captures.
Update your Helm values
After the upgrade completes successfully, update your Helm values file to use the PostgreSQL 16 image for future deployments.
Add the following override:
This ensures that subsequent helm upgrade operations continue using the PostgreSQL 16 image. Without this override, a future helm upgrade can revert the PostgreSQL StatefulSet to the PostgreSQL 14 image.
Roll back to PostgreSQL 14
This rollback procedure applies only if the actual pg_upgrade --link step fails. The script interactively prompts for confirmation before running the real upgrade. All steps before that prompt are pre-upgrade checks and are safe to abort without rollback. If the upgrade completes successfully, no rollback is needed.
If the upgrade fails after the --link step:
Scale down the StatefulSet:
Delete the upgraded PostgreSQL data volume (PVC).
Restore PostgreSQL using the same backup method you selected in Backup and restore options.
The exact restore steps depend on the method:
VolumeSnapshot or cloud disk snapshot: Recreate the
data-postgres-0PVC from your snapshot (see the restore steps for that method), then set the image back to PostgreSQL 14 and scale up (step 4).pg_dumpwith the provided script: Set the image back to PostgreSQL 14, scale up so Kubernetes recreates an empty PVC and starts the pod, then restore into the running database. For example:
If you restored from a VolumeSnapshot or cloud disk snapshot (and have not already done so), set the image back to PostgreSQL 14 and scale up:
Run
ANALYZE(statistics reset after restore):Verify restored data by comparing against the pre-upgrade baseline:
Compare the output report with the pre-upgrade verification file:
Troubleshooting
Backup and restore options
Choose one of the following options based on your environment:
Use your existing backup process
If you already have a backup process in place, such as Velero, a cloud-native backup service, or scheduled pg_dumpall jobs, continue using it. Ensure you have a restorable backup taken after a CHECKPOINT:
Then take the backup using your existing process. For rollback, follow your existing restore procedure to recreate the data-postgres-0 PVC.
Back up with pg_dump
Backup:
Restore:
Verify (on-demand):
The verify action runs ANALYZE and captures database sizes and per-table row counts. Use it to generate a report at any point and compare against a prior baseline.
A row-count verification report is also generated automatically after backup and restore operations.
Use Kubernetes VolumeSnapshot
Prerequisites:
The PVC uses a CSI-based StorageClass that implements VolumeSnapshot (in-tree provisioners, NFS, EFS, Local PV, and RWX volumes do not support snapshots).
A
VolumeSnapshotClasswhose driver matches your StorageClass provisioner.
Installing CRDs and the snapshot-controller requires cluster-level permissions. Ensure these installations are approved for your cluster.
Install VolumeSnapshot CRDs (if not already present):
If you see volumesnapshots.snapshot.storage.k8s.io, volumesnapshotcontents.snapshot.storage.k8s.io, and volumesnapshotclasses.snapshot.storage.k8s.io, skip to the next step. Otherwise install them:
Install snapshot-controller (if not running):
GKE: The snapshot-controller is managed by Google on the control plane. No installation needed.
EKS: AWS does not include the snapshot-controller. Check if already running:
If not running, install it:
Create a VolumeSnapshotClass (if not present):
Find your provisioner:
GCP (GKE with Persistent Disk CSI):
AWS (EKS with EBS CSI):
Create a snapshot:
Wait until the READYTOUSE field changes to true.
snapshot.yaml:
Restore from VolumeSnapshot:
Use a direct cloud disk snapshot
Use this option if your storage platform supports native disk snapshots. This works for any PV regardless of how it was provisioned. No VolumeSnapshot CRDs, snapshot-controller, or CSI format requirement needed.
Prerequisites:
CLI access to the cloud account (
gcloud,aws, oraz).
Take snapshot:
GCP:
For other cloud providers, refer to your provider documentation for taking a disk snapshot (for example, aws ec2 create-snapshot for AWS, az snapshot create for Azure).
Restore from cloud disk snapshot:
Create a new disk from the snapshot, then create a PV and PVC pointing to it.
GCP:
Create a PV pointing to the restored disk:
Create a PVC bound to it:
For other cloud providers, the disk create command differs per provider. The PV/PVC structure is the same. Only the csi.driver, csi.volumeHandle, and the nodeAffinity zone label change per provider.
Included scripts
These scripts are in the scripts directory of the Harness Helm chart:
pg-upgrade.sh
Main upgrade script (PG14 to PG16) with built-in data verification
pg-backup-restore.sh
Logical backup, restore, and on-demand data verification using pg_dump
Last updated
Was this helpful?