Skip to content

PostgreSQL backups

DataQI uses CloudNativePG (CNPG) External link; internet access required to manage its PostgreSQL clusters. When backups are enabled, CNPG provides:

  • Continuous WAL archiving — individual transaction logs are streamed to the destination as they are written, providing a low recovery point objective (RPO).
  • Scheduled base backups — periodic full backups taken on a configurable cron schedule.
  • Point-in-time recovery (PITR) — any base backup combined with its WAL archive allows restoration to any point in time within the retention window.

Backups are disabled by default and can be configured independently per cluster.


Each of the three managed CNPG clusters — pg-api, pg-audit, and pg-keycloak — has its own backup configuration block nested under databases.<cluster>.backup. This means you can configure different retention periods, schedules, or destination paths for each cluster, or enable backups for only a subset of them.

Backup is enabled for a cluster simply by providing a non-empty barmanObjectStore block. No separate enabled flag is needed.

The chart accepts any valid CNPG barmanObjectStore specification as a pass-through value. This means any storage backend supported by Barman Cloud works without chart changes — including Azure Blob Storage, AWS S3, Google Cloud Storage, and S3-compatible on-premises stores such as MinIO.


Configure backups per cluster by adding a backup sub-block under the relevant database key. You only need to configure the clusters you want to back up:

databases:
api:
backup:
retentionPolicy: "30d" # How long to retain base backups (default: 30d)
schedule: "0 2 * * *" # Cron schedule for base backups (default: 02:00 UTC daily)
barmanObjectStore:
# Provider-specific configuration — see examples below
audit:
backup:
retentionPolicy: "90d" # Audit data often needs longer retention
schedule: "0 2 * * *"
barmanObjectStore:
# Can be a different destination to api

Create a Kubernetes secret containing your storage account credentials:

Terminal window
kubectl create secret generic pg-backup-creds \
--from-literal=storage-account=<account-name> \
--from-literal=storage-key=<account-key>

Then configure the barmanObjectStore under each database you want to back up:

databases:
api:
backup:
retentionPolicy: "30d"
schedule: "0 2 * * *"
barmanObjectStore:
destinationPath: "https://<account>.blob.core.windows.net/<container>/pg-api"
azureCredentials:
storageAccount:
name: pg-backup-creds
key: storage-account
storageKey:
name: pg-backup-creds
key: storage-key
wal:
compression: gzip
data:
compression: gzip
audit:
backup:
retentionPolicy: "90d" # Example: longer retention for audit data
schedule: "0 2 * * *"
barmanObjectStore:
destinationPath: "https://<account>.blob.core.windows.net/<container>/pg-audit"
azureCredentials:
storageAccount:
name: pg-backup-creds
key: storage-account
storageKey:
name: pg-backup-creds
key: storage-key
wal:
compression: gzip
data:
compression: gzip

AKS Workload Identity: If your cluster uses Azure Workload Identity, you can avoid a credentials secret entirely by annotating the CNPG service account with your managed identity client ID and replacing the azureCredentials block with inheritFromAzureAD: true. The managed identity must have the Storage Blob Data Contributor role on the container.


Terminal window
kubectl create secret generic pg-backup-creds \
--from-literal=ACCESS_KEY_ID=<key> \
--from-literal=ACCESS_SECRET_KEY=<secret>
databases:
api:
backup:
retentionPolicy: "30d"
schedule: "0 2 * * *"
barmanObjectStore:
destinationPath: "s3://<bucket>/pg-api"
s3Credentials:
accessKeyId:
name: pg-backup-creds
key: ACCESS_KEY_ID
secretAccessKey:
name: pg-backup-creds
key: ACCESS_SECRET_KEY
wal:
compression: gzip
data:
compression: gzip

For environments without public internet access, MinIO External link; internet access required provides an S3-compatible object store that can run entirely within your Kubernetes cluster or on bare metal. It supports full WAL archiving and PITR with no cloud dependency.

Deploy MinIO into your cluster first (for example, using the MinIO Operator External link; internet access required or a simple StatefulSet), then point barmanObjectStore at it using endpointURL:

Terminal window
kubectl create secret generic pg-backup-creds \
--from-literal=ACCESS_KEY_ID=<minio-access-key> \
--from-literal=ACCESS_SECRET_KEY=<minio-secret-key>
databases:
api:
backup:
retentionPolicy: "30d"
schedule: "0 2 * * *"
barmanObjectStore:
destinationPath: "s3://<bucket-name>/pg-api"
endpointURL: "http://minio.minio-ns.svc.cluster.local:9000"
s3Credentials:
accessKeyId:
name: pg-backup-creds
key: ACCESS_KEY_ID
secretAccessKey:
name: pg-backup-creds
key: ACCESS_SECRET_KEY
wal:
compression: gzip
data:
compression: gzip

TLS: If your MinIO instance is configured with TLS, use https:// in endpointURL and ensure the relevant CA certificate is trusted by the CNPG pods. See the custom CA bundle guide for details.


Once backups are enabled and the clusters have started, you can inspect backup status using kubectl:

Terminal window
# List scheduled backup resources
kubectl get scheduledbackups -n <namespace>
# Inspect a specific cluster's backup status
kubectl get cluster pg-api -n <namespace> -o jsonpath='{.status.lastSuccessfulBackup}'
# View all completed backup objects
kubectl get backups -n <namespace>

A healthy cluster will show a lastSuccessfulBackup timestamp on the cluster status, and individual Backup objects will reach completed phase.


The retentionPolicy field controls how many days of base backups are retained. WAL segments are retained automatically to cover the oldest available base backup.

For point-in-time recovery, refer to the CNPG recovery documentation External link; internet access required. Recovery is performed by bootstrapping a new cluster from an existing backup using the bootstrap.recovery stanza — this is outside the scope of the DataQI Helm chart and is performed directly via CNPG.