CloudNativePG
A Kubernetes operator that runs PostgreSQL as a Cluster custom resource: it creates one pod and one volume per instance, manages streaming replication, failover and rolling updates with its own controller, and publishes rw/ro/r Services. Backups go through the Barman Cloud plugin, which archives WAL continuously and stores base backups in S3, GCS or Azure, so a cluster can be restored to any point in its recovery window. Apache 2.0 and free. Fits any team that wants Postgres on Kubernetes declared in Git, with point-in-time recovery, and without a managed database service.
CloudNativePG (CNPG) is an open-source Kubernetes operator for PostgreSQL. A single Cluster manifest declares the instances, storage, configuration and backup target, and the operator keeps the running database in that state: it provisions pods and volumes, sets up replication, promotes a replica when the primary fails and points the Services at the new primary. Its companion, the Barman Cloud plugin, ships the write-ahead log and base backups to object storage so that a database can be rebuilt at any moment inside its retention window.
What it is
The operator manages vanilla PostgreSQL on vanilla Kubernetes only. It does not support forks of Postgres or other databases. Licence is Apache 2.0. EDB created the project, and it was accepted into the CNCF as a Sandbox project in January 2025.
The current minor line is 1.30 (1.30.0 on 2026-06-29, 1.30.1 on 2026-09-23, released the same day as 1.29.3). According to the project's support table, 1.30 supports Kubernetes 1.34 to 1.36 and PostgreSQL 14 to 18, and its end of life is about December 2026. A minor release stays supported until three months after the next minor ships. The 1.30.1 default operand image is PostgreSQL 18.6 on Debian 13 (trixie).
The resource family is Cluster, Backup, ScheduledBackup, Pooler (PgBouncer), Database, Publication, Subscription, ImageCatalog / ClusterImageCatalog and, new in 1.30, DatabaseRole for one role per manifest. The operator extends through CNPG-I, a gRPC plugin interface. The Barman Cloud plugin (plugin-barman-cloud, also Apache 2.0) is the first major plugin. Its current release is v0.15.1 (2026-09-30, bundling Barman 3.20.1). It needs CloudNativePG 1.26 or later and cert-manager. It replaces the in-tree .spec.backup.barmanObjectStore support, which has been deprecated since 1.26 and is now scheduled for removal in 1.31.0.
How it works
The operator does not use a StatefulSet. Its own controller creates one pod and one PVC for each instance, so it can tell a primary from a replica, resize volumes and update replicas before it does a switchover of the primary. Each pod runs an instance manager as its entry point. The instance manager starts Postgres, reports health to the operator and serves metrics. The operator creates three ClusterIP Services for each cluster: <cluster>-rw (primary only), <cluster>-ro (replicas only) and <cluster>-r (any instance). Applications that use -rw follow the primary across failovers without a change in configuration.
With the plugin, the operator asks the plugin (over gRPC with TLS) to add a Barman Cloud sidecar to every instance pod. That sidecar runs barman-cloud to archive each WAL segment, to take base backups and to fetch WAL during a restore. An ObjectStore resource holds the bucket path, endpoint, credentials, compression and retention policy. In the bucket, WAL goes under wals/ and base backups go as tarballs under base/.
Step 1 of 5. When it builds an instance pod for a Cluster whose spec.plugins lists barman-cloud.cloudnative-pg.io, the operator calls the plugin. The plugin adds the Barman sidecar to the pod.
Barman Cloud plugin flows: continuous WAL archiving, a scheduled base backup, and a point-in-time restore into a new cluster.
The three paths share the bucket. The archive is continuous, and the base backups set where a restore starts. The retention window therefore sets how far back a point-in-time restore can go. A restore always creates a new Cluster. It never rewinds a running one.
When to use it
Reach for it when:
- Postgres needs to run inside Kubernetes, declared in Git next to the applications that use it.
- Point-in-time recovery to object storage is a requirement, not a nice-to-have.
- Failover, replica scaling and minor-version rolling updates should be automatic.
- The cluster is self-hosted (homelab, on-prem, edge) and a managed database service is not an option or not wanted.
Skip it when:
- A managed service (RDS, Cloud SQL, Azure Flexible Server) is already available and its cost is acceptable. A managed service does the same job without an operator to upgrade.
- The cluster has no reliable persistent storage. CNPG expects a StorageClass, and local-path volumes tie each instance to one node.
- The database must be a Postgres fork or carry features that only exist in a fork.
- The team does not want to own WAL, backup and restore drills. The operator automates those jobs, but the team still owns the outcome.
At a glance
Core concepts
- Cluster — the database: instance count, image, storage,
postgresql.parameters,bootstrap(initdb,recoveryorpg_basebackup) andplugins. - Instance manager — PID 1 in every instance pod. It controls Postgres locally, and the operator talks to it.
- Services —
-rw,-roand-rper cluster. These default names are reserved. Extra Services can be declared under.spec.managed.services.additional. - ObjectStore (
barmancloud.cnpg.io/v1) — the bucket, endpoint, credentials, WAL and data options, andretentionPolicy. The docs recommend one ObjectStore per cluster. - Backup / ScheduledBackup — on-demand and cron-driven base backups, with
method: pluginwhen the plugin is used. - Primary Lease (new in 1.30) — a Kubernetes
Leasethat serializes promotion. The docs call it a promotion gate, not a fence.
Key facts
| Aspect | Value |
|---|---|
| Operator release line | 1.30 (1.30.1, 2026-09-23); 1.29 reached end of life 2026-09-29 |
| Plugin release | v0.15.1 (2026-09-30), Barman 3.20.1 |
| Kubernetes (1.30 support table) | 1.34, 1.35, 1.36 |
| PostgreSQL majors | 14 to 18 |
| Plugin prerequisites | CNPG 1.26 or later (1.27 or later recommended), cert-manager, same namespace as the operator |
| Object stores | Amazon S3 and S3-compatible stores, Google Cloud Storage, Azure Blob Storage |
| Licence | Apache 2.0 (operator and plugin) |
Compared with other Postgres operators
| Aspect | CloudNativePG | Zalando postgres-operator | Crunchy PGO |
|---|---|---|---|
| HA mechanism | Own controller and instance manager | Patroni in StatefulSets | Patroni |
| Backup tool | Barman Cloud plugin | WAL-G / WAL-E | pgBackRest |
| Governance | CNCF Sandbox | Zalando | Crunchy Data |
| Licence | Apache 2.0 | MIT | Apache 2.0 |
How to integrate
Install cert-manager first, then install the operator and the plugin from the official chart repository:
helm repo add cnpg https://cloudnative-pg.github.io/charts
helm repo update
helm upgrade --install cnpg --namespace cnpg-system --create-namespace cnpg/cloudnative-pg
helm upgrade --install plugin-barman-cloud --namespace cnpg-system cnpg/plugin-barman-cloud
kubectl -n cnpg-system rollout status deploy/plugin-barman-cloud
Declare the object store and a cluster that archives to it:
apiVersion: barmancloud.cnpg.io/v1
kind: ObjectStore
metadata:
name: pg-backups
spec:
retentionPolicy: "14d"
configuration:
destinationPath: s3://postgres/
endpointURL: http://s3.example.svc:8333 # any S3-compatible endpoint
s3Credentials:
accessKeyId: { name: pg-backup-s3, key: ACCESS_KEY_ID }
secretAccessKey: { name: pg-backup-s3, key: ACCESS_SECRET_KEY }
wal:
compression: gzip
---
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: pg
spec:
instances: 1
imageName: ghcr.io/cloudnative-pg/postgresql:17
storage:
size: 20Gi
plugins:
- name: barman-cloud.cloudnative-pg.io
isWALArchiver: true
parameters:
barmanObjectName: pg-backups
---
apiVersion: postgresql.cnpg.io/v1
kind: ScheduledBackup
metadata:
name: pg-nightly
spec:
schedule: "0 0 3 * * *" # six fields: seconds first
backupOwnerReference: self
cluster:
name: pg
method: plugin
pluginConfiguration:
name: barman-cloud.cloudnative-pg.io
A point-in-time restore is a new cluster:
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: pg-restore
spec:
instances: 1
storage:
size: 20Gi
bootstrap:
recovery:
source: origin
recoveryTarget:
targetTime: "2026-10-16 21:30:00+00"
externalClusters:
- name: origin
plugin:
name: barman-cloud.cloudnative-pg.io
parameters:
barmanObjectName: pg-backups
serverName: pg
On-demand backups and status come from the kubectl cnpg plugin: kubectl cnpg backup pg --method=plugin --plugin-name=barman-cloud.cloudnative-pg.io and kubectl cnpg status pg.
In the GL stack
CloudNativePG 1.30.1 with the Barman Cloud plugin v0.15.1 runs the shared Postgres on both the beta and the prod cluster. It holds one database for each product, paiddaily.io and sagedaily.io among them.
- Image. The cluster runs a Postgres 17.11 image with the pgTAP extension added. Product business logic lives in stored procedures.
- Backups. WAL is archived continuously, and a base backup is taken every night. Both go to the S3 backup store, which is SeaweedFS on the management cluster, in its
postgresbucket. Retention is 14 days. A point-in-time restore has been drilled, not only configured. A nightlypg_dumpof each database runs as a second, logical copy. - Split with Velero. Velero's volume policy skips the CNPG volumes. Barman Cloud is the backup of record for Postgres data, and Velero covers the rest of each namespace.
- Migration without app changes. The Services keep the names of the Postgres deployment that came before, so every connection string kept working when the database moved under the operator.
- Beta data. Beta databases are snapshots refreshed from prod.
- Restarts. Restart an instance by deleting its pod. The operator recreates the pod on the same volume.
kubectl rollout restartdoes nothing useful here because no Deployment or StatefulSet owns the pod.
Gotchas
- The in-tree backup goes away in 1.31.
.spec.backup.barmanObjectStorehas been deprecated since 1.26, and the 1.30.0 notes move its removal to 1.31.0. Migrate before that upgrade: translate the stanza into anObjectStore, then switch theCluster, theScheduledBackups and theexternalClustersin one change. - The plugin lives with the operator. It must be installed in the operator's namespace (normally
cnpg-system), and cert-manager must be ready first, or the plugin's certificates are not issued and the install fails. - Deployment names differ by install method. The Helm chart creates
deploy/plugin-barman-cloud. The kubectl manifest createsdeploy/barman-cloud. Runbooks and alerts must use the right name. - Leave
serverNameempty on the ObjectStore. It exists for API compatibility only. SetserverNameas a plugin parameter on the Cluster or inexternalClusters. - Six-field cron.
ScheduledBackup.schedulestarts with seconds.0 0 * * *is not the Kubernetes CronJob meaning. Write0 0 0 * * *for midnight. - A restored cluster does not archive by default. Add
.spec.pluginsto the recovery cluster, and give it its ownserverNameor path. Barman checks that the WAL archive is empty before the first archive, so a restored cluster that points at the source's archive fails that check. clusterreferences are immutable since 1.30. AScheduledBackup,Database,Pooler,PublicationorSubscriptioncannot be pointed at another cluster. The API server rejects the change, so delete and recreate the object.- Backup metric names changed. The plugin exports
barman_cloud_cloudnative_pg_io_last_available_backup_timestamp,..._last_failed_backup_timestampand..._first_recoverability_point. These replace the oldercnpg_collectorbackup metrics, so update alert rules that use the old names. - Plugin upgrades are not zero-downtime. The plugin Deployment uses the
Recreatestrategy. Extra replicas protect against node loss, not against the short gap during an upgrade.
Risks
- Fast support window. About one minor release every three months, and each minor is supported only until three months after the next one. 1.30 is due for end of life around December 2026. Plan regular operator upgrades.
- Backup path in transition. The plugin is at v0.x, and the in-tree path is about to be removed. Expect API and parameter changes, and read the release notes on every bump.
- Vendor weight. CNCF governance and Apache 2.0 reduce lock-in, but EDB created the project and its engineers remain central to it. Kubernetes distributions other than vanilla, such as OpenShift, are not officially supported or tested.
- Backups are only as good as the last restore. WAL archiving can fail without notice when a bucket fills or a credential rotates. Alert on the age of the last backup and on archive failures, and drill restores on a schedule.
- Credentials in the bucket path. The S3 keys can read every base backup and every WAL segment. Scope them to the one bucket, and treat the bucket as production data.
Alternatives
- Managed Postgres (RDS, Cloud SQL, Azure Flexible Server) — choose it when the database can live outside the cluster and paying for operations is better than running an operator.
- Zalando postgres-operator — choose it for a Patroni-based HA model and an existing WAL-G backup setup.
- Crunchy PGO — choose it when the team wants pgBackRest as the backup tool.
- Plain StatefulSet with scheduled
pg_dump— choose it for a single small database where a restore to last night's dump is acceptable and point-in-time recovery is not needed.
Related
- Postgres — the database the operator runs, with the stack's database-per-product and stored-procedure conventions.
- SeaweedFS and MinIO — the S3 backup store that holds WAL and base backups, and the application object store.
- Velero — namespace backups that skip the CNPG volumes.
- cert-manager — issues the TLS certificates between the operator and the plugin.
- Prometheus — scrapes the instance manager and the backup metrics.
- Data layer overview and Backup layer overview.
- Official: CloudNativePG docs, cloudnative-pg releases, Barman Cloud plugin docs, plugin-barman-cloud releases.
