Overview
CDC Pipeline deploys a complete change data capture stack in a single release. It reimplements nothing: it bundles three catalog templates as dependencies — PostgreSQL Highly Available as the source database, Kafka as the event transport, and Debezium Server as the connector that reads the database’s change stream and publishes every row-level insert, update and delete to Kafka. This chart adds only the glue: a policy letting the Kafka brokers read the one credentials secret you create, the internal hostnames each component uses to reach the others, and checks at render time that the components’ values agree.What Gets Created
Prerequisites
Create the credentials secret
my-cdc-pipeline-credentials is the name the values default to:sourcePasswordmust equalpassword(Debezium reads that key), andusername/databasemust equaldebezium-server.source.database.user/.name.databaseis used unquoted, so keep it to lowercase letters, digits and underscores.kafkaSaslPasswordis the password of Kafka’sdebeziumuser, on the broker side and in Debezium alike.kafkaAdminPasswordis the Kafkaadminuser’s; the other two secure the brokers’ own connections. Keep the Kafka passwords to letters and digits, as generated above: they are placed inside Kafka’s login configuration, where a"or;breaks it.- The secret’s name appears in six values:
postgres-highly-available.config.credentialsSecretName,debezium-server.credentialsSecretNameand the fourkafka.kafka.enventries (see Database Credentials). All six must name the same secret; the chart refuses anything else. Secret names are org-wide, so give each release its own, and do not useRELEASE_NAME-debezium-credentials, which Debezium creates itself.
Optional: create the Kafbat UI configuration secret
ADMIN_PASSWORD with the credentials secret’s kafkaAdminPassword (read it with cpln secret reveal my-cdc-pipeline-credentials -o yaml) and UI_PASSWORD with the login you want for the console. The full file format is in the Kafbat configuration reference.kafka.kafbat_ui.enabled to true and kafka.kafbat_ui.configuration_secret to this name. If you do not want the console, skip this step.Choose the KRaft cluster ID
change-me-cdc-pipeline-kraft-cluster-id is a placeholder, so replace it. Generate it with the Kafka tooling, using the same image the brokers run:Installation
Install into an existing GVC once the credentials secret exists. With the default secret namemy-cdc-pipeline-credentials, only the KRaft cluster ID is required:
-f values.yaml), as shown under Database Credentials.
UI
CLI
Terraform
Pulumi
Configuration
Each block shows the shipped defaults for one area ofvalues.yaml. Only the keys you change need to go in your values file. The bundled components take their own values under postgres-highly-available, kafka and debezium-server; the linked component pages explain each option, but this release pins older component versions than those pages describe.
Database Credentials
Every credential of the pipeline comes from the one secret created in Prerequisites. Its name appears in six values, and all six must name the same secret:PostgreSQL Highly Available
Kafka
The broker, listener, ACL and secret settings, plus the optional consoles. Every Kafka password is a${env:VAR} reference, never the password: the broker resolves it from one of the CDC_KAFKA_* variables in kafka.kafka.env (Kafka’s EnvVarConfigProvider), and the chart refuses a plain password. kafka.jmx_exporter and kafka.kafka_client ship with working defaults; see Kafka for them.
kafka.kafka.env entry reading it (cpln://secret/SECRET_NAME.NEW_KEY), and append the user and ${env:THAT_VARIABLE} to users and passwords. Kafka Connect (kafka.kafka_connectors) is refused at render, because its worker login and plugin configuration take credentials inline; Debezium Server is this pipeline’s connector, so install the Kafka template on its own to run Kafka Connect.
Debezium Server
The connector’s source and sink.hostname and bootstrapServers are filled in from the release name when left empty, so the defaults already point at the bundled database and brokers.
debezium_heartbeat table and, once wal_level is logical, the debezium replication slot in the source database, so the heartbeat needs no manual SQL. Pointing hostname or bootstrapServers at a database or Kafka outside this release still deploys the bundled components, and the render-time credential checks still apply. Debezium reads its database and Kafka passwords from the credentials secret named by debezium-server.credentialsSecretName.
Connecting
Nothing in the pipeline is public except Kafbat UI. Everything else is reachable from inside the GVC.dbserver1. topic appears, read the connector log and see Troubleshooting:
admin, add it as described under Kafka (a new key in the credentials secret, a kafka.kafka.env entry, and the user and its ${env:VAR} reference appended to users and passwords), and give it access, either with Kafka ACLs or by listing it in kafka.kafka.acl.superUsers.
Operations
Backing Up
Every volume set in the pipeline takes a final snapshot when it is deleted and keeps it for seven days; the Kafka log volume sets also take a snapshot daily at 00:00 UTC. Take extra snapshots before a risky change. The source database is the system of record:RELEASE_NAME-debezium-data record how far the connector has read; losing them makes it snapshot the source again from the start:
pg_dumpall or WAL-G to object storage) are switched off here with postgres-highly-available.backup.enabled: false. Turning them on through this chart has not been verified; see PostgreSQL Highly Available for how they work in the standalone template.
Restoring a Backup
Restoring any of this pipeline’s volume snapshots has not been verified. A restored database whose replication slot no longer matches the Debezium offsets, or Kafka brokers whose metadata no longer matches their peers, may not resume cleanly. Rely on PostgreSQL and Kafka replication for the loss of a single member, and treat snapshots as a last resort.Upgrading from 1.0.1
Versions 1.0.0 and 1.0.1 bundle a PostgreSQL Highly Available release that does not compact its etcd cluster, so etcd’s backend grows with time alone until it reaches its 2 GiB quota and goes read-only, taking PostgreSQL failover with it. Every install of those versions is affected, because the database cannot be switched off. Upgrading to 1.0.2 or later turns compaction on and stops further growth, but it cannot shrink a backend that has already grown, and a cluster that has already raised aNOSPACE alarm needs operator recovery rather than an upgrade. The mechanism and the checks are on the PostgreSQL Highly Available page under etcd History Compaction.
Upgrading from 1.0.3
Version 1.0.4 moved the database credentials. They used to bepostgres-highly-available.postgres.username, .password, .database and .walLevel; they are now database.username, database.password, database.name and database.walLevel, and this chart creates the credentials secret named by postgres-highly-available.config.credentialsSecretName. Old keys left under postgres-highly-available.postgres are no longer read.
An existing database keeps the credentials it was created with, so set database.* to those exact values; different values leave the members unable to authenticate after their next restart. Recover them before upgrading, from your values file or from the secret the earlier version created:
Upgrading from 1.0.4
1.0.4 never delivered change events (wal_level was replica and Debezium had no Kafka permissions), so a fresh install of 1.1.1 is the simplest path: install it as a new release, move any data the database holds, then uninstall the old release. To upgrade in place instead:
-
1.0.4 created the database secret itself, and this upgrade deletes it; it also kept Kafka’s passwords as values, which 1.1.x reads from the secret instead. Before upgrading, create the new secret under a new name holding the values the database and the Kafka cluster run with today, not new ones — the running cluster keeps its passwords, and nothing changes on it. Read the database credentials from
my-cdc-pipeline-db-credentials(or the name inpostgres-highly-available.config.credentialsSecretName), the Kafkaclient-admin-password,inter-broker-passwordandcontroller-passwordfromRELEASE_NAME-secrets, and Debezium’skafka-sasl-passwordfromRELEASE_NAME-debezium-credentials: -
In your values, delete the
database:block,debezium-server.source.database.passwordanddebezium-server.sink.kafka.saslPassword; set bothcredentialsSecretNamekeys to the new name; and if you changedkafka.kafka.acl.superUsers, addUser:debezium. Replace every Kafka password with its reference and add thekafka.kafka.enventries and provider lines exactly as in Kafka and Database Credentials, naming the new secret; delete anykafka.kafka_exporterblock (1.1.x runs no Kafka exporter or health sidecar). The chart refuses the old keys and any plain Kafka password at render. -
Before upgrading, switch the running cluster to
wal_level = logical— 1.0.4 created it withreplica, and 1.1.x replicas refuse to start on areplicacluster, which stalls the upgrade. The same command tells Patroni to leave logical slots alone and removes the install-time password 1.0.4 stored in the cluster configuration ("authentication":null; without it this command prints that password back to you). Then restart the members in place, the replicas first and the leader last (patronictldoes not work on 1.0.4’s cluster, so this uses Patroni’s API;LOCATIONis your GVC’s location):Run theclustercall again: every member should berunningorstreamingwith nopending_restart. -
Upgrade. The upgrade restarts the bundled PostgreSQL too (it now reads the new secret), so Debezium can briefly lose its database; it reconnects by itself. The Kafka brokers restart as well, now reading their passwords from the secret. The new version of a workload can also wait several minutes with
is not allowed to reveal the secretinget-deployments, while access to the new secret propagates; the previous version keeps serving meanwhile, and it clears by itself. -
Confirm Debezium’s slot is a failover slot:
pgx N psql -h 127.0.0.1 -d postgres -c "SELECT slot_name, failover FROM pg_replication_slots"on the leader showsfailover = t. If it showsf(1.0.4’s Debezium created it), stop the connector, convert the slot from anypsqlthat reaches the current leader (the slot must be inactive), then start the connector again:
Upgrading from 1.1.1 or earlier
1.1.2 moves the database tocontrolplanecorporation/patroni-postgres:0.8, which carries pgvector 0.8.7 (CVE-2026-103484). The database members restart and nothing limits that rollout, so expect a brief interruption of writes while the leader changes. The upgrade does not redeploy Debezium; it restarts once when the database leader changes and resumes from its failover replication slot, so changes around the leader change may be delivered twice. Upgrade in a quiet window. Existing data needs nothing. If you pinned postgres-highly-available.image, set it to the 0.8 tag: tags 0.1 to 0.7 are refused at render. The pipeline does not use the vector extension; if you created it in your database, run ALTER EXTENSION vector UPDATE; there, which only updates the version \dx reports.
Rotating the Database Password in HA Mode
The HA database needs its own order. The replication rolerepl shares the password, and a member that restarts with the old password can be promoted to leader, which splits the cluster. Move the leader to member -0 first, so it restarts last, after every other member already has the new password. pgx runs a command in one member (LOCATION is your GVC’s location, DB_USERNAME the secret’s username):
password and sourcePassword, confirm it, and restart the members:
streaming replicas on one timeline (repeat step 1); -0 restarts last, so the leader moves once more, to another member. For a release upgraded from 1.0.4 that skipped "authentication":null in its upgrade, also remove the install-time password Patroni kept in its cluster configuration:
ALTER ROLE until you have edited the secret: its container then restarts by itself and reads the new sourcePassword, so it needs no redeploy of its own. If it still logs password authentication failed a few minutes after the edit, run cpln workload force-redeployment RELEASE_NAME-debezium --gvc GVC_NAME.
Any helm upgrade after the secret has been edited restarts RELEASE_NAME-postgres-ha, RELEASE_NAME-cluster and RELEASE_NAME-debezium again (one more rolling restart of the database, with its leader changes), even when no value changed, because they are rolled whenever the secret they read has changed since the last upgrade. Plan the next upgrade into the same window. If a member stays starting, or running without streaming for several minutes, re-copy it from the leader. This copies the whole database, so it costs network traffic in proportion to its size:
Rotating the Kafka Passwords
All four Kafka passwords live only in the credentials secret, so a rotation is a secret edit and two redeployments, with nohelm upgrade. The brokers and Debezium keep the passwords they started with until they restart, so run the steps back to back: a broker that restarts on its own in between comes back with passwords its peers do not have yet.
kafkaInterBrokerPassword or kafkaControllerPassword changed, a restarted broker cannot rejoin the brokers still on the old passwords, so partway through the roll Kafka refuses writes until the last broker has restarted; rotate those two in a quiet window. Debezium is refused from step 3 until step 4, then resumes from its replication slot, so nothing is lost and events around the switch can be delivered twice. Any other client that logs in as admin or debezium needs the new password too.
Scaling and Availability
- The source database runs three Patroni members behind HAProxy and fails over automatically when the leader is lost; Debezium connects through HAProxy, which routes to the current leader, and its startup step creates the replication slot.
- Kafka runs three brokers with a replication factor of 3.
kafka.kafka.replicasaccepts 1, 3, 4 or 5; see Kafka for the rules. - Debezium Server is a single replica and cannot be scaled out.
- Keep
postgres-highly-available.etcd.replicasodd, and choose it at install time.
Troubleshooting
Debezium is running but no change events reach Kafka
Debezium is running but no change events reach Kafka
wal_level = replica, which pgoutput logical decoding cannot use; database.walLevel is validated but not applied. Kafka enforces ACLs with allowEveryoneIfNoAclFound: false, and the debezium user is neither a super user nor granted any ACL.Fix: read the connector log, filtered server-side, to see which applies:User:debezium to kafka.kafka.acl.superUsers puts it in the brokers’ super-user list. Patroni keeps wal_level in its cluster-wide configuration, so it is not changed by any value of this chart. Neither change has been verified end to end on this template.Kafbat UI never becomes ready and cpln logs shows nothing
Kafbat UI never becomes ready and cpln logs shows nothing
kafka.kafbat_ui.configuration_secret did not exist when the workload was created. The container never starts, so there is no log output.Fix: read status.versions[].message from cpln workload get-deployments RELEASE_NAME-kafbat-ui --gvc GVC_NAME -o yaml to see which secret is missing, create it as shown in Prerequisites, then wait a few minutes or run cpln workload force-redeployment RELEASE_NAME-kafbat-ui --gvc GVC_NAME.Install fails because the credentialsSecretName values must name the SAME secret
Install fails because the credentialsSecretName values must name the SAME secret
postgres-highly-available.config.credentialsSecretName, debezium-server.credentialsSecretName and the four kafka.kafka.env entries do not all name one secret.Fix: set all six to the name of your credentials secret, as shown under Database Credentials.Install or upgrade fails with was REMOVED in 1.1.0 or Kafka's passwords are no longer values
Install or upgrade fails with was REMOVED in 1.1.0 or Kafka's passwords are no longer values
database:, debezium-server.source.database.password, debezium-server.sink.kafka.saslPassword) or a plain Kafka password.Fix: follow Upgrading from 1.0.4.Install fails with Kafka SASL mismatch
Install fails with Kafka SASL mismatch
debezium-server.sink.kafka.saslUsername does not appear in kafka.kafka.listeners.client.sasl.users.Fix: add the user to the Kafka list, or set saslUsername to a user already in it.Install fails with postgres-highly-available.walLevel must be logical for CDC
Install fails with postgres-highly-available.walLevel must be logical for CDC
postgres-highly-available.walLevel was set to something other than logical.Fix: leave it at logical.Two releases in one org use the same database credentials secret
Two releases in one org use the same database credentials secret
my-cdc-pipeline-credentials by default, without the release name, and secrets are org-wide.Fix: give every release in the org its own credentials secret, and set all six values that name it.Source disk fills with WAL
Source disk fills with WAL
debezium-server.source.postgres.slotName changed. PostgreSQL keeps WAL for an inactive slot indefinitely.Fix: drop the abandoned slot on the source, using its name:Important Notes
- Never turn
postgres-highly-available.multiZone,postgres-highly-available.etcd.multiZoneorkafka.kafka.multiZoneoff once it has been on. Each replica’s volume stays in the zone it was created in, so with multi-zone off a replica whose volume is in another zone cannot be scheduled and the rollout stops at it. Turning one on later is safe.cpln helm upgradedoes not reuse earlier values, so keep the setting in your values file on every upgrade. To recover, upgrade again with it on, then force a redeployment of the affected workload. - In version 1.0.4 the pipeline does not deliver change events with its defaults; see Troubleshooting and verify events arrive before relying on it.
- Create the credentials secret before installing; a missing secret wedges the deployment silently, and only
status.versions[].messagefromcpln workload get-deploymentsnames it. - All six values that name the credentials secret must name the same one; the chart refuses anything else.
- Rotating the database password in HA mode needs a leader switchover first; follow Rotating the Database Password in HA Mode. A plain redeploy can promote a member still holding the old password and split the cluster.
- Rotating a Kafka password needs both redeployments; see Rotating the Kafka Passwords.
- This template runs no Kafka exporter, health sidecar, REST Proxy or Kafka Connect, because each needs a password inline; the chart refuses them.
kafka.kafka.secrets.kraft_cluster_idis fixed once the brokers have started.- Kafbat UI is open to the internet by default; set a strong console login or narrow
kafka.kafbat_ui.firewall.external_inboundAllowCIDR. - Give each release its own credentials secret; the default name is shared org-wide.
- Uninstalling deletes every volume set — the source database, the Kafka topics and the Debezium offsets; final snapshots are kept for seven days.
- Component versions are pinned in this chart (PostgreSQL Highly Available 2.5.0, Kafka 4.0.1, Debezium Server 1.1.1) and change only with a new CDC Pipeline version.