Restore PostgreSQL (CloudNativePG)
This document describes how to restore a CloudNativePG cluster from backups or VolumeSnapshots.
Recovery Options
CloudNativePG supports multiple recovery methods:
- Barman Cloud Backup - Restore from S3-stored backups
- VolumeSnapshot - Restore from Longhorn snapshots
- pg_basebackup - Clone from an existing cluster
Recovery from Barman Cloud Backup
Prerequisites
- ObjectStore resource configured with S3 credentials
- Existing backups in the S3 bucket
- CNPG operator running
Recovery Cluster Manifest
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: <app>-db-recovered
namespace: <namespace>
spec:
instances: 1
imageName: ghcr.io/cloudnative-pg/postgresql:18
storage:
size: 20Gi
storageClass: longhorn
bootstrap:
recovery:
source: <app>-backup
externalClusters:
- name: <app>-backup
plugin:
name: barman-cloud.cloudnative-pg.io
parameters:
barmanObjectName: <app>-minio-store
Point-in-Time Recovery (PITR)
To recover to a specific point in time:
bootstrap:
recovery:
source: <app>-backup
recoveryTarget:
targetTime: "2024-01-15 10:30:00"
Recovery from VolumeSnapshot
Prerequisites
- Longhorn VolumeSnapshot exists
- Snapshot contains valid PGDATA
Create Snapshot (if needed)
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: <app>-pgdata-backup
namespace: <namespace>
spec:
volumeSnapshotClassName: longhorn-snapshot
source:
persistentVolumeClaimName: <app>-db-1
Recovery from Snapshot
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: <app>-db-recovered
namespace: <namespace>
spec:
instances: 1
imageName: ghcr.io/cloudnative-pg/postgresql:18
storage:
size: 20Gi
storageClass: longhorn
bootstrap:
recovery:
volumeSnapshots:
storage:
name: <app>-pgdata-backup
kind: VolumeSnapshot
apiGroup: snapshot.storage.k8s.io
Verification Steps
Check Cluster Status
# Watch cluster initialization
kubectl get cluster <cluster-name> -n <namespace> -w
# Check pod logs during recovery
kubectl logs -n <namespace> <cluster-name>-1 -f
Verify Data Integrity
# Port forward to the cluster
kubectl port-forward -n <namespace> svc/<cluster-name>-rw 5432:5432 &
# Connect and verify
psql -h localhost -U <user> -d <database> -c '\dt'
psql -h localhost -U <user> -d <database> -c 'SELECT COUNT(*) FROM <table>;'
Troubleshooting
Cluster Stuck in Recovery
Check operator logs:
kubectl logs -n cnpg-system deployment/cnpg-controller-manager --tail=100
VolumeSnapshot Issues
Verify snapshot is ready:
kubectl get volumesnapshot -n <namespace>
kubectl describe volumesnapshot <snapshot-name> -n <namespace>
Permission Issues
CNPG expects PGDATA owned by UID/GID 26:26. If restoring from a foreign snapshot:
# Check permissions inside the pod
kubectl exec -n <namespace> <pod-name> -- ls -la /var/lib/postgresql/data/
Post-Recovery Tasks
- Update application configs - Point applications to the new cluster service
- Verify credentials - Check the auto-generated
<cluster-name>-appsecret - Enable backups - Add ObjectStore and ScheduledBackup resources
- Scale replicas - Increase instances after primary is healthy
Reference
For detailed disaster recovery scenarios, see Zalando to CNPG Migration which documents a real-world recovery case.