11---
22title : " CloudNativePG and Crunchy PGO: an honest, opinionated comparison"
3- date : 2026-05-16T09:00:00 +10:00
3+ date : 2026-05-18T16:54:47 +10:00
44description : " A personal comparison of CloudNativePG and Crunchy PGO, covering architecture, image design, backup, upgrades, observability, licensing and community health."
55tags : ["postgresql", "postgres", "kubernetes", "k8s", "cloudnativepg", "cnpg",
66 " dok" , "data on kubernetes", "crunchy", "pgo", "operator", "comparison",
@@ -109,40 +109,39 @@ the new primary regardless of its name or index. StatefulSet-bound ordinal logic
109109cannot express that kind of decision natively; it requires a separate
110110coordination layer, which is exactly what Patroni provides in PGO's case.
111111
112- Direct Pod management also enables CloudNativePG to coordinate updates to
113- sensitive PostgreSQL parameters (those that must be equal to or greater on a
114- standby than on the primary, such as ` max_connections ` and ` max_wal_senders ` ) in
115- the correct order across the cluster . With StatefulSets, that kind of
116- coordinated sequencing requires logic on top of the primitive.
112+ Direct Pod management also enables CloudNativePG to coordinate configuration
113+ changes across the cluster in the correct order, including parameters that
114+ must be set to equal or higher values on standbys than on the primary before
115+ any change is applied . With StatefulSets, that kind of coordinated sequencing
116+ requires additional logic on top of the primitive.
117117
118118## The Instance Manager
119119
120120There are no HA management sidecars in CloudNativePG. The management logic runs
121121as an Instance Manager, a Go binary that acts as PID 1 inside the PostgreSQL
122122container. It handles the full Postgres lifecycle, participates in self-healing
123123and communicates directly with the Kubernetes API to report health, replication
124- lag and LSN.
125-
126- The probes it exposes to the Kubelet are database-aware rather than generic. The
127- startup probe prevents the Kubelet from restarting the pod during ` initdb ` ,
128- recovery or WAL replay. The readiness probe validates ` pg_isready ` on the
129- primary and, when configured, checks replication lag on replicas before
130- allowing traffic. The liveness probe on the primary performs an isolation
131- check: if both the API server and peer instances become simultaneously
132- unreachable, the probe deliberately fails, causing the Kubelet to restart the
133- pod after 30 seconds (configurable). This mitigates the risk of data loss from
134- a possible split-brain by taking the isolated primary offline (a scenario that
135- cannot arise when synchronous replication is in use). It is worth noting
136- that
137- Patroni introduced a similar capability in
124+ lag and position.
125+
126+ What makes this particularly relevant is how the Instance Manager interacts
127+ with the Kubelet through health probes that are database-aware rather than
128+ generic. The startup probe prevents the Kubelet from restarting the pod
129+ during initialisation or recovery. The readiness probe checks whether the
130+ instance is ready to serve traffic, including replication lag on replicas when
131+ configured. The liveness probe on the primary performs an isolation check: if
132+ both the API server and peer instances become simultaneously unreachable, the
133+ probe deliberately fails, causing the Kubelet to restart the pod and take the
134+ isolated primary offline. This mitigates the risk of a split-brain scenario
135+ (though it cannot arise when synchronous replication is in use). Patroni
136+ introduced a similar capability in
138137[ version 3.0.0] ( https://github.com/patroni/patroni/blob/master/docs/releases.rst#version-300 )
139138through its [ DCS failsafe mode] ( https://github.com/patroni/patroni/pull/2379 ) .
140139CloudNativePG independently implemented the same concept the Kubernetes way:
141140rather than querying peers over a REST API, it lets the liveness probe and
142141the Kubelet do the work. The discussion that led to our implementation is
143- [ here] ( https://github.com/cloudnative-pg/cloudnative-pg/discussions/7462 ) . It is
144- a good example of how the same problem can be solved with fundamentally
145- different primitives depending on your execution environment.
142+ [ here] ( https://github.com/cloudnative-pg/cloudnative-pg/discussions/7462 ) ,
143+ and it is a good example of how the same problem can be solved with
144+ fundamentally different primitives depending on your execution environment.
146145
147146## On Kubernetes API server availability
148147
@@ -161,10 +160,10 @@ triggering a failover, and attempting to do so without a reliable view of the
161160full cluster state would introduce risk rather than remove it. Suspending
162161those decisions and prioritising data protection is therefore not a limitation
163162so much as the honest consequence of a design that trusts a single,
164- authoritative source of truth. It is also worth noting that Kubernetes itself is designed to address control
165- plane availability risks through deployment across multiple availability
166- zones, making a full API server outage an increasingly unlikely event in a
167- properly configured cluster. In our view, the more robust answer for scenarios
163+ authoritative source of truth. It is also worth noting that Kubernetes itself
164+ is designed to address control plane availability risks through deployment
165+ across multiple availability zones, making a full API server outage an
166+ increasingly unlikely event in a properly configured cluster. In our view, the more robust answer for scenarios
168167where the control plane itself is at risk is a resilient multi-region
169168architecture, which CloudNativePG supports through its
170169[ distributed topology] ( https://cloudnative-pg.io/docs/current/replica_cluster#distributed-topology )
@@ -182,11 +181,12 @@ The architectural choice to embed nothing but PostgreSQL in the operand image
182181has direct consequences for image size and security posture. Crunchy's operand
183182image bundles Patroni (and its Python runtime), pgBackRest, pgAudit, pgvector,
184183TimescaleDB, pg_cron, pg_partman and other extensions into a single UBI9-based
185- image, because they all need to be co-located for Patroni to function. CloudNativePG's minimal image
186- contains only PostgreSQL, with extensions delivered at runtime as OCI image
187- volumes via the Kubernetes ` ImageVolume ` feature (requires PostgreSQL 18 or
188- later and Kubernetes 1.35 or later, where ` ImageVolume ` is enabled by default;
189- it can be enabled via feature gate on 1.33 and 1.34), covered in detail in
184+ image, because they all need to be co-located for Patroni to function.
185+ CloudNativePG's minimal image contains only PostgreSQL, with extensions
186+ delivered at runtime as OCI image volumes via the Kubernetes ` ImageVolume `
187+ feature (requires PostgreSQL 18 or later and Kubernetes 1.35 or later, where
188+ ` ImageVolume ` is enabled by default; it can be enabled via feature gate on
189+ 1.33 and 1.34), covered in detail in
190190[ CNPG Recipe 23] ({{< relref "../20251201-extensions/index.md" >}}). Adding or
191191removing an extension is a declarative change to the ` Cluster ` manifest; it
192192does not require a different base image and, crucially, does not break
@@ -204,15 +204,17 @@ source image, zero critical vulnerabilities against two and four high against
204204156 . Its Debian Trixie Slim base has zero known vulnerabilities of its own. The
205205package count matters operationally: fewer packages means a smaller blast radius
206206for any future disclosure and a shorter list to audit. The CNPG minimal image
207- also ships with a full SBOM provenance attestation.
207+ also ships with a full Software Bill of Materials (SBOM) provenance
208+ attestation.
208209
209210On the topic of image licensing: Crunchy Data's container images have
210211historically been distributed under the
211212[ Crunchy Data Developer Program] ( https://www.crunchydata.com/developers/terms-of-use ) ,
212213which restricts production use for organisations with more than 50 employees.
213214The operator itself is open-source; the images it uses by default have not
214- always been. Whether this has changed following the Snowflake acquisition is something
215- to verify directly with Crunchy before making a procurement decision.
215+ always been. Whether this has changed following the Snowflake acquisition is
216+ something to verify directly with Crunchy before making a procurement
217+ decision.
216218Every image in the CloudNativePG ecosystem — operator, operand, extension images
217219— is fully open-source under the Apache License 2.0.
218220
@@ -268,9 +270,8 @@ restore. At
268270[ KubeCon Atlanta 2023] ( https://www.youtube.com/watch?v=WGQq4MWzW6E ) , we
269271demonstrated a 2-minute recovery of a 4.5 TB database using this approach.
270272
271- The second is the plugin interface (
272- [ CNPG-I] ( https://cloudnative-pg.io/docs/current/cnpg_i ) ), which decouples backup
273- tooling from the operator entirely. The Barman Cloud Plugin is the reference
273+ The second is [ CNPG-I] ( https://cloudnative-pg.io/docs/current/cnpg_i ) , a
274+ plugin interface that decouples backup tooling from the operator entirely. The Barman Cloud Plugin is the reference
274275implementation and the only one currently maintained by the community, but the
275276interface is open: nothing prevents the community or organisations from writing
276277plugins for other tools such as pgBackRest or WAL-G.
@@ -354,11 +355,12 @@ debt across three areas that are consuming most of our cognitive budget right
354355now: extension image support (where the work is almost complete), the migration
355356from the in-core Barman Cloud integration to the plugin model (also nearing
356357completion) and the refactoring of the end-to-end test suite to work with
357- CNPG-I plugins. Once these tracks land, the review surface narrows considerably and the
358- backlog should follow.
358+ CNPG-I plugins. Once these tracks land, the review surface narrows
359+ considerably and the backlog should follow.
359360
360361CloudNativePG is a [ CNCF Sandbox project] ( https://www.cncf.io/ ) , currently
361- [ in the queue for incubation] ( https://github.com/cncf/toc/issues/1961 ) , with health metrics publicly visible on the
362+ [ in the queue for incubation] ( https://github.com/cncf/toc/issues/1961 ) , with
363+ health metrics publicly visible on the
362364[ LFX Insights dashboard] ( https://insights.linuxfoundation.org/project/cloudnativepg ) .
363365The main repository has 8.6k stars; across all repositories in the CloudNativePG
364366GitHub organisation, the total reaches nearly 10,000. The majority of the
@@ -409,9 +411,10 @@ the backup model.
409411
410412If you are evaluating PostgreSQL operators today and your primary concerns are
411413long-term architectural soundness, open governance and a community with visible
412- momentum, I think the data presented here is worth reflecting on carefully. That is my opinion, and I hold it knowing it is not neutral. It
413- cannot be, coming from a maintainer and founder of the project (had we not
414- thought it differently from the start, there would be no CloudNativePG now).
414+ momentum, I think the data presented here is worth reflecting on carefully.
415+ That is my opinion, and I hold it knowing it is not neutral. It cannot be,
416+ coming from a maintainer and founder of the project (had we not thought it
417+ differently from the start, there would be no CloudNativePG now).
415418
416419Ultimately, the choice is yours. My honest advice, bias acknowledged, is to try
417420both and decide what fits your team, your workload and your organisation best.
0 commit comments