Point-in-Time Recovery allows restoring the database to a specific moment in time rather than to the latest available state.
This is useful in scenarios such as recovering from a corrupted database state, reverting changes caused by a failed Keycloak upgrade, or undoing an unintended data modification.
PITR relies on continuous WAL archiving, which is already configured when using the Barman Cloud plugin as described in Deploying CloudNativePG with scheduled backups to S3.
CloudNativePG automatically selects the base backup closest to the specified target time and replays the WAL logs up to that point.
|
|
Before upgrading Keycloak, record the current timestamp or transaction ID so it can be used as a recovery target if the upgrade fails.
The timestamp can be obtained by running:
date -u +"%Y-%m-%dT%H:%M:%SZ"
|
To perform a Point-in-Time Recovery, add a recoveryTarget section to the bootstrap.recovery configuration.
The following example recovers the cluster to a specific timestamp:
-
Create a cluster-recovery-pitr.yaml file based on the following content:
Cluster PITR resource:
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: cnpg-keycloak
spec:
instances: 3
storage:
size: 8Gi
affinity:
podAntiAffinityType: required
topologyKey: topology.kubernetes.io/zone
postgresql:
synchronous:
method: any
number: 1
dataDurability: required
parameters:
max_connections: "100"
bootstrap:
recovery:
source: source
recoveryTarget: (1)
targetTime: "2026-03-30T10:00:00Z" (2)
managed:
services:
disabledDefaultServices: ["ro", "r"]
plugins:
- name: barman-cloud.cloudnative-pg.io
isWALArchiver: true
parameters:
barmanObjectName: cnpg-store
serverName: cnpg-keycloak-pitr (3)
externalClusters:
- name: source
plugin:
name: barman-cloud.cloudnative-pg.io
parameters:
barmanObjectName: cnpg-store
serverName: cnpg-keycloak
| 1 |
The recoveryTarget section specifies the target state to which the database is recovered.
See the table below for all supported target options. |
| 2 |
The target timestamp in RFC 3339 format.
Always include an explicit timezone to avoid ambiguity.
Replace this value with the timestamp recorded before the upgrade or the desired recovery point. |
| 3 |
The serverName must be unique for each recovery to prevent overwriting backup data in the object store.
The following table lists all supported recovery target options.
Only one option can be used at a time:
| Option |
Description |
targetTime
|
Timestamp up to which recovery proceeds, expressed in RFC 3339 format (for example, 2026-03-30T10:00:00Z). Always include an explicit timezone. |
targetXID
|
Transaction ID up to which recovery proceeds. Note that transactions may complete in a different numeric order than their assignment order. |
targetName
|
Named restore point created with the PostgreSQL function pg_create_restore_point() to which recovery proceeds. |
targetLSN
|
Write-ahead log location (Log Sequence Number) up to which recovery proceeds. |
targetImmediate
|
Recovery ends as soon as a consistent state is reached, that is, as early as possible. |
-
Apply the PITR cluster resource:
Command:
kubectl -n cnpg-keycloak apply -f cluster-recovery-pitr.yaml
-
Wait for the cnpg-keycloak cluster to get into the Ready state.
Command:
kubectl -n cnpg-keycloak wait --for condition=Ready --timeout=300s cluster cnpg-keycloak
Output:
cluster.postgresql.cnpg.io/cnpg-keycloak condition met
|