Skip to content

feat(cloudnative-pg): add CloudNativePG operator + Cluster catalog entry - #337

Merged
patrick-hermann-sva merged 1 commit into
mainfrom
feat/cloudnative-pg
Aug 29, 2026
Merged

patrick-hermann-sva merged 1 commit into
mainfrom
feat/cloudnative-pg

Conversation

@patrick-hermann-sva

Copy link
Copy Markdown
Contributor

Adds infra/cloudnative-pg — CloudNativePG as a catalog entry, in two independent sub-entries, both sourcing https://cloudnative-pg.github.io/charts:

Sub-entry Chart Version Sync wave
install/ cnpg/cloudnative-pg (operator) 0.29.0 (app 1.30.0) -10
cluster/ cnpg/cluster (the Cluster CR) 0.8.1 0

Port of the Helmfile definitions in stuttgart-things/helm#161.

Why

Three catalog entries each carry their own bundled Bitnami PostgreSQL — apps/backstage/install, apps/zitadel/install, and apps/harbor/install (the last pinned to bitnamilegacy/postgresql, a deprecation shim). apps/zitadel/install/values.yaml already says in its own comment to point ZITADEL at managed PostgreSQL for production. This entry is the shared answer.

Migrating those three is not part of this PR — that means data movement and a per-app credentials rewire, and it belongs in its own change.

infra/ rather than apps/ because CNPG is a dependency of other catalog entries, which puts it alongside external-secrets and cert-manager. apps/redis-stack is a surface-level analog but a leaf — nothing in the catalog consumes it.

Shape

Follows the house pattern: apps/redis-stack/install for the computed-valuesObject shape, infra/longhorn/install for a plain-HTTPS chart repo. Four files per sub-entry plus one entry README. Strict values.schema.json (additionalProperties: false); extraValues and syncPolicy stay open.

Split into two sub-entries because the lifecycles genuinely differ — one operator per cluster, N databases against it. cluster/ derives its Application name from clusterName + destination (not destination alone), so several Postgres clusters can share one target cluster without colliding.

Decisions worth a reviewer's eye

  • install/ defaults destination.namespace to postgres, not upstream's cnpg-system — matching stuttgart-things/helm's database/postgres.yaml.gotmpl. Consistency across the sibling repos; documented in the README so nobody "fixes" it.
  • ServerSideApply is required, not stylistic. The clusters.postgresql.cnpg.io CRD is far past the 262144-byte last-applied-configuration annotation limit, so a client-side apply fails outright.
  • cluster/ emits cluster.initdb.secret only when appSecretName is non-empty. An empty secret.name breaks CNPG bootstrap; empty means CNPG generates <clusterName>-app itself.
  • owner is schema-constrained to exclude { / } because upstream runs cluster.initdb.owner through tpl.
  • The retry block is load-bearing. Sync waves only order resources within one Application, so syncing cluster/ against a cluster whose operator isn't up yet fails the dry-run on the unknown postgresql.cnpg.io/v1 kind; retry (limit 5, exponential to 3m) is what recovers it. Documented rather than papered over.
  • cluster/'s destination.namespace has no good default — a Cluster belongs in the consuming app's namespace, not the operator's. It is required in the schema, and values.yaml carries an inert placeholder (cnpg-cluster) purely so the chart renders standalone for CI. Because Helm deep-merges maps, a consumer overriding only destination.server inherits that placeholder — called out prominently in the README. If you'd prefer a hard render-time required instead, that trades away a green bare helm template.
  • Root README gains the infra/ row only. The entry counts in that index are already stale (infra/ claims 8, holds 11 now); reconciling it is its own change.

Validation

  • helm lint + helm template clean on both sub-entries.
  • Rendered child Applications confirmed for repoURL (https://cloudnative-pg.github.io/charts), chart, targetRevision, and sync-wave.
  • Both valuesObjects fed back through the real upstream charts. The operator renders 11 CRDs (matching the documented teardown list); the cluster chart renders a Cluster with the expected instances / storage / walStorage / enablePDB / bootstrap.initdb — including secret.name appearing only when appSecretName is set — plus PodMonitor + PrometheusRule when monitoring is on, and extraValues deep-merging into cluster.* alongside the computed keys.
  • Schema strictness verified live: an unknown key and a braces-bearing owner are both rejected.
  • Renovate annotations checked against the renovate.json customManager regex — both match with the right depName (cloudnative-pg / cluster) and registryUrl.

Not done: no platforms/storage ApplicationSet (the brief marks it optional/on-request), and no live-cluster apply from this branch.

🤖 Generated with Claude Code

https://claude.ai/code/session_018THyZwQsAgdoZSC4ZY4eGf

Adds infra/cloudnative-pg with two independent sub-entries, both sourcing
https://cloudnative-pg.github.io/charts:

- install/  cnpg/cloudnative-pg 0.29.0 (app 1.30.0), sync-wave -10
- cluster/  cnpg/cluster 0.8.1 (the official Cluster CR chart), sync-wave 0

Split because the lifecycles differ: one operator per cluster, N databases
against it. cluster/ derives its Application name from clusterName +
destination so several Postgres clusters can share a target cluster.

Three catalog entries (backstage, zitadel, harbor) each carry a bundled
Bitnami Postgres, one of them pinned to bitnamilegacy. This entry is the
shared managed alternative; migrating those three is deliberately not part
of this change.

Notes:
- destination.namespace defaults to `postgres` for install/, matching
  stuttgart-things/helm's database/postgres.yaml.gotmpl rather than
  upstream's cnpg-system. Documented in the README so nobody "fixes" it.
- ServerSideApply is required, not stylistic: the clusters.postgresql.cnpg.io
  CRD exceeds the 262144-byte last-applied-configuration annotation limit.
- cluster/ emits cluster.initdb.secret only when appSecretName is non-empty;
  an empty secret.name breaks CNPG bootstrap.
- owner is schema-constrained to exclude `{}` because upstream runs
  cluster.initdb.owner through tpl.

Root README gains the infra/ row only; the stale entry counts in that index
are left alone.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018THyZwQsAgdoZSC4ZY4eGf
@patrick-hermann-sva
patrick-hermann-sva merged commit c48d46c into main Aug 29, 2026
5 checks passed
@patrick-hermann-sva
patrick-hermann-sva deleted the feat/cloudnative-pg branch August 29, 2026 16:14
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 0.10.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

This branch was previously deployed

1 inactive deployment
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant