From 45bd81e88f1f0d4505fae2ed21ffe98201ec3afa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20No=C3=ABl?= Date: Sun, 17 May 2026 21:33:28 -0700 Subject: [PATCH] feat(cluster): expose replicationSlots on the CNPG Cluster MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Surfaces CloudNativePG's `spec.replicationSlots` on the cluster chart so chart users can enable synchronization of user-created logical replication slots between the primary and standbys. With PostgreSQL 17+ failover slots, this lets CDC consumers (e.g. Debezium) survive a CNPG failover without losing the slot. To make logical decoding slots survive failover, users must: - enable `cluster.replicationSlots.highAvailability.synchronizeLogicalDecoding` - set `cluster.postgresql.parameters.hot_standby_feedback: "on"` - set `cluster.postgresql.parameters.sync_replication_slots: "on"` - create the CDC client's logical slot with `failover = true` Requires CloudNativePG 1.27+ and PostgreSQL 17+ for native failover slots. The block is omitted entirely when the value is empty, so existing deployments are unaffected. The non-default-configuration chainsaw test is extended with a `replicationSlots` block and the matching PostgreSQL parameters, and asserts they appear verbatim on the rendered Cluster CR. Signed-off-by: Philippe Noël --- charts/cluster/README.md | 1 + charts/cluster/templates/cluster.yaml | 5 +++ ..._default_configuration_cluster-assert.yaml | 8 +++++ .../01-non_default_configuration_cluster.yaml | 8 +++++ charts/cluster/values.schema.json | 33 +++++++++++++++++++ charts/cluster/values.yaml | 14 ++++++++ 6 files changed, 69 insertions(+) diff --git a/charts/cluster/README.md b/charts/cluster/README.md index af64bcdaef..840564ab3e 100644 --- a/charts/cluster/README.md +++ b/charts/cluster/README.md @@ -192,6 +192,7 @@ Kubernetes: `>=1.29.0-0` | cluster.primaryUpdateMethod | string | `"switchover"` | Method to follow to upgrade the primary server during a rolling update procedure, after all replicas have been successfully updated. It can be switchover (default) or restart. | | cluster.primaryUpdateStrategy | string | `"unsupervised"` | Strategy to follow to upgrade the primary server during a rolling update procedure, after all replicas have been successfully updated: it can be automated (unsupervised - default) or manual (supervised) | | cluster.priorityClassName | string | `""` | | +| cluster.replicationSlots | object | `{}` | Replication slot management. To make logical decoding slots survive failover for CDC consumers (e.g. Debezium), enable `highAvailability.synchronizeLogicalDecoding`, set `cluster.postgresql.parameters.hot_standby_feedback: "on"` and `cluster.postgresql.parameters.sync_replication_slots: "on"`, and ensure the CDC client creates its logical slot with `failover = true`. Requires CloudNativePG 1.27+ and PostgreSQL 17+ for native failover slots. See: https://cloudnative-pg.io/documentation/current/replication/#replication-slots | | cluster.resources | object | `{}` | Resources requirements of every generated Pod. Please refer to https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ for more information. We strongly advise you use the same setting for limits and requests so that your cluster pods are given a Guaranteed QoS. See: https://kubernetes.io/docs/concepts/workloads/pods/pod-qos/ | | cluster.roles | list | `[]` | This feature enables declarative management of existing roles, as well as the creation of new roles if they are not already present in the database. See: https://cloudnative-pg.io/documentation/current/declarative_role_management/ | | cluster.securityContext | object | `{}` | Configure Container Security Context. See: https://cloudnative-pg.io/documentation/preview/security/ | diff --git a/charts/cluster/templates/cluster.yaml b/charts/cluster/templates/cluster.yaml index 4a17479773..dad210387e 100644 --- a/charts/cluster/templates/cluster.yaml +++ b/charts/cluster/templates/cluster.yaml @@ -98,6 +98,11 @@ spec: {{- toYaml . | nindent 6 }} {{- end }} + {{- with .Values.cluster.replicationSlots }} + replicationSlots: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- if not (and (empty .Values.cluster.roles) (empty .Values.cluster.services)) }} managed: {{- with .Values.cluster.services }} diff --git a/charts/cluster/test/postgresql-cluster-configuration/01-non_default_configuration_cluster-assert.yaml b/charts/cluster/test/postgresql-cluster-configuration/01-non_default_configuration_cluster-assert.yaml index 47439b88dd..daf4b1bcf1 100644 --- a/charts/cluster/test/postgresql-cluster-configuration/01-non_default_configuration_cluster-assert.yaml +++ b/charts/cluster/test/postgresql-cluster-configuration/01-non_default_configuration_cluster-assert.yaml @@ -12,6 +12,12 @@ spec: postgresUID: 1001 postgresGID: 1002 instances: 2 + replicationSlots: + highAvailability: + enabled: true + slotPrefix: "_cnpg_" + synchronizeLogicalDecoding: true + updateInterval: 30 postgresql: ldap: server: 'openldap.default.svc.cluster.local' @@ -23,7 +29,9 @@ spec: key: 'data' searchAttribute: 'uid' parameters: + hot_standby_feedback: "on" max_connections: "42" + sync_replication_slots: "on" pg_hba: - host all 1.2.3.4/32 trust pg_ident: diff --git a/charts/cluster/test/postgresql-cluster-configuration/01-non_default_configuration_cluster.yaml b/charts/cluster/test/postgresql-cluster-configuration/01-non_default_configuration_cluster.yaml index 16a048c17c..27a6e2a697 100644 --- a/charts/cluster/test/postgresql-cluster-configuration/01-non_default_configuration_cluster.yaml +++ b/charts/cluster/test/postgresql-cluster-configuration/01-non_default_configuration_cluster.yaml @@ -87,6 +87,12 @@ cluster: inRoles: - pg_monitor - pg_signal_backend + replicationSlots: + highAvailability: + enabled: true + slotPrefix: "_cnpg_" + synchronizeLogicalDecoding: true + updateInterval: 30 postgresql: ldap: server: 'openldap.default.svc.cluster.local' @@ -98,7 +104,9 @@ cluster: key: 'data' searchAttribute: 'uid' parameters: + hot_standby_feedback: "on" max_connections: "42" + sync_replication_slots: "on" pg_hba: - host all 1.2.3.4/32 trust pg_ident: diff --git a/charts/cluster/values.schema.json b/charts/cluster/values.schema.json index 85645a49a7..26948d6e1c 100644 --- a/charts/cluster/values.schema.json +++ b/charts/cluster/values.schema.json @@ -322,6 +322,39 @@ "priorityClassName": { "type": "string" }, + "replicationSlots": { + "type": "object", + "properties": { + "highAvailability": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "slotPrefix": { + "type": "string" + }, + "synchronizeLogicalDecoding": { + "type": "boolean" + } + } + }, + "synchronizeReplicas": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "excludePatterns": { + "type": "array" + } + } + }, + "updateInterval": { + "type": "integer" + } + } + }, "resources": { "type": "object" }, diff --git a/charts/cluster/values.yaml b/charts/cluster/values.yaml index 2c7e8b5c15..3be0ca1165 100644 --- a/charts/cluster/values.yaml +++ b/charts/cluster/values.yaml @@ -379,6 +379,20 @@ cluster: # key: 'data' # searchAttribute: 'uid' + # -- Replication slot management. To make logical decoding slots survive + # failover for CDC consumers (e.g. Debezium), enable + # `highAvailability.synchronizeLogicalDecoding`, set + # `cluster.postgresql.parameters.hot_standby_feedback: "on"` and + # `cluster.postgresql.parameters.sync_replication_slots: "on"`, and ensure + # the CDC client creates its logical slot with `failover = true`. + # Requires CloudNativePG 1.27+ and PostgreSQL 17+ for native failover slots. + # See: https://cloudnative-pg.io/documentation/current/replication/#replication-slots + replicationSlots: {} + # highAvailability: + # enabled: true + # slotPrefix: "_cnpg_" + # synchronizeLogicalDecoding: true + # updateInterval: 30 # -- BootstrapInitDB is the configuration of the bootstrap process when initdb is used. # See: https://cloudnative-pg.io/documentation/current/bootstrap/