Releases: hops-ops/psql-stack
v0.8.0
What's changed in v0.8.0
-
feat(psqlcluster): add targetNamespace field (by @patrickleet)
Decouples the PSQLCluster XR's control-plane namespace from the composed
CNPG Cluster's data-plane namespace. Defaults to the XR's own ns (the
common case); override when the XR lives in the platform default ns but
the data plane needs to land elsewhere — e.g. embedded in AuthStack so
Zitadel pods can env-var-mount the app Secret without cross-namespace
mirroring.Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
See full diff: v0.7.0...v0.8.0
v0.7.0
What's changed in v0.7.0
-
feat: pivot psql-stack to EKS Auto Mode defaults (#10) (by @patrickleet)
- feat: optional NodePool for dedicated psql workloads
Add opt-in Karpenter NodePool composed resource. When
spec.nodePool.enabled: true, renders a NodePool targeting arm64 spot on
r7g.large/r7g.xlarge/m7g.large/m7g.xlarge (memory-optimized Graviton),
tainted with psql=true:NoSchedule and labeled workload-type: psql.StackGres (operator/restapi/jobs) and Atlas get nodeSelector + tolerations
injected into their Helm values when the NodePool is enabled. Usages pin
both releases to be drained before the NodePool is deleted. Adds
provider-kubernetes to upbound.yaml for the NodePool Object wrapper.Implements [[tasks/psql-stack-vela-simplyblock]]
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- feat: StorageClass + ExternalSecrets composed resources
- storageClass (default on): creates a gp3 StorageClass backed by the
EKS Auto Mode EBS CSI driver (ebs.csi.eks.amazonaws.com). The legacy
gp2 in-tree provisioner does not work on EKS Auto Mode. - externalSecrets (opt-in): for each entry in externalSecrets.secrets[],
composes a kubernetes.m.crossplane.io/Object wrapping an ESO
ExternalSecret that syncs an AWS Secrets Manager value (published via
hops secrets sync aws) into a Kubernetes Secret on the target cluster.
Requires a ClusterSecretStore (e.g. from SecretStack); defaults to
clusterSecretStoreName: hops-aws-secrets-manager.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- fix: default StorageClass name to 'psql' (per-stack naming)
Mirrors observe stack where StorageClasses are named loki/prometheus/tempo
per-component. Keeps the name specific to the stack so it doesn't collide
with cluster-provided defaults.Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- feat: externalSecrets.connections[] composes password + config → URL
Replaces the generic externalSecrets.secrets[] passthrough with a
Postgres-specific connections[] API. The user publishes just a password
via hops secrets (single JSON key, default 'password'); the stack
combines it with non-secret host/port/database/username/sslmode/namespace
and emits a K8s Secret with a ready-to-use 'url' key plus discrete fields.Downstream consumers reference whichever key they need:
AtlasSchema.devURLFrom → url
SGCluster credentials.users.superuser.password → password
applications → url (or discrete fields)Breaking change to the (locally-only) externalSecrets API; redeploy with
the new shape.Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- refactor: drop externalSecrets from PSQLStack
Without managing the SGCluster, every field in externalSecrets.connections[]
(host/port/database/namespace) is passthrough — no abstraction. Users write
ExternalSecret CRs directly (or as a Crossplane Object wrapper in local/)
against the ClusterSecretStore provisioned by SecretStack.PSQLStack now = platform only: StackGres + Atlas operators + NodePool +
StorageClass. If we later add an instances[] that composes SGClusters,
ESO wiring can come back for free since the stack will then know
host/port/database/namespace without the user restating them.Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- feat: swap StackGres operator for CloudNativePG (phase 1 of CNPG pivot)
Rewrites PSQLStack schema to remove stackgresOperator, add cnpg and
scaleToZeroPlugin blocks. Default namespace: cnpg-system. CNPG 1.29
(chart 0.27.1) replaces StackGres 1.18 as the operator. Atlas operator
renumbered 210 → 220 to make room for the scale-to-zero plugin
install (added in a later phase).Storage (psql StorageClass on EBS gp3) and NodePool blocks preserved
unchanged — phases 2 and 3 will rewrite them for the three-profile
(mayastor / lvm / ebs) storage model and the branches/primary NodePool
split with hugepages + nvme-tcp pre-configured.Implements [[tasks/psql-stack-cnpg]]
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- feat: three-profile storage layer — mayastor + lvm + ebs (phase 2)
Replaces the single storageClass block with a storage block exposing three
independent profiles:- storage.mayastor (replicated NVMe-oF via OpenEBS Mayastor) — enterprise
default for primary serving clusters; CoW + HA across N replicas. Default
enabled=false until phase 3 lands the NodePool with hugepages + nvme-tcp. - storage.lvm (single-node CoW via OpenEBS LVM LocalPV) — branches and dev
clusters. Default enabled=false until phase 3 lands NodePool LVM volume
groups. - storage.ebs (EBS gp3 via EKS Auto Mode CSI) — durable fallback, no CoW;
always-on default.
Render templates:
- 120-storageclass.yaml.gotmpl deleted (was the single 'psql' SC)
- 160-openebs-lvm.yaml.gotmpl: Helm release for OpenEBS LVM LocalPV
- 165-openebs-mayastor.yaml.gotmpl: Helm release for OpenEBS Mayastor
- 170-storageclass-mayastor.yaml.gotmpl: psql-mayastor SC + VolumeSnapshotClass
- 175-storageclass-lvm.yaml.gotmpl: psql-lvm SC + VolumeSnapshotClass
- 180-storageclass-ebs.yaml.gotmpl: psql-ebs SC (renamed from 'psql')
state-init defaults the three profile blocks; state-status observes the new
resource keys. Mayastor + LVM Helm releases + their StorageClasses are gated
on storage.{mayastor,lvm}.enabled — only EBS materializes by default until
phase 3 unblocks the others.standard.yaml example patched to drop the removed storageClass and
stackgresOperator fields (full example rewrite is phase 5).Implements [[tasks/psql-stack-cnpg]]
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- feat: split NodePool into branches + primary sub-pools (phase 3)
Replaces the single Karpenter NodePool with two sub-pools targeting NVMe
arm64 instance-store nodes (i4g.2xlarge / i4g.4xlarge / im4gn.2xlarge):- nodePool.branches: spot — for ephemeral PSQLBranch workloads. Spot is
acceptable since branches are reproducible. - nodePool.primary: on-demand — for PSQLCluster primaries and operators
(CNPG, Atlas, scale-to-zero). Spot preemption would lose a Mayastor
replica, so on-demand is the right default for serving workloads.
Each sub-pool has its own labels (sub-pool=branches | sub-pool=primary)
and matching taints so workloads can target one specifically. Operators
ride the primary sub-pool via nodeSelector + tolerations injected from
state-init.Render templates:
- 150-nodepool.yaml.gotmpl deleted
- 140-nodepool-branches.yaml.gotmpl: spot sub-pool
- 145-nodepool-primary.yaml.gotmpl: on-demand sub-pool + Usage protection
for CNPG/Atlas Releases against premature NodePool deletion.
state-init defaults the new sub-pool blocks; state-status observes both.
nodePool.enabled stays default-false — existing claims unchanged.Out of scope for this commit: node-side prep for Mayastor + LVM
(hugepages, nvme-tcp module, LVM volume group on instance-store NVMe).
That's phase 3b (a separate concern that needs careful image / runtime
choices) — without it, mayastor.enabled and lvm.enabled won't bind PVCs.Implements [[tasks/psql-stack-cnpg]]
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- feat: install cnpg-i-scale-to-zero plugin (phase 4)
Inlines the upstream cnpg-i-scale-to-zero v0.1.7 release manifest as 9
Crossplane Kubernetes Objects:- ServiceAccount cnpg-scale-to-zero-plugin
- ClusterRole cnpg-scale-to-zero-sidecar-role + ClusterRoleBinding
- Secret scale-to-zero-config (sidecar image reference, paired to plugin
version via stringData — k8s base64-encodes on apply) - Self-signed cert-manager Issuer + 2 Certificates (server + client) for
the gRPC TLS material the CNPG operator uses to reach the plugin - Service scale-to-zero (cnpg.io/pluginPort=9090, cnpg.io/pluginName
annotations) - Deployment scale-to-zero (the plugin gRPC server)
Plugin and sidecar images both pin to spec.scaleToZeroPlugin.version
(default v0.1.7). Secret is renamed scale-to-zero-config (was
scale-to-zero-config-c2c2544fbk in upstream — drops the kustomize
hash suffix since we emit the resources as separate Objects).All resources are gated on spec.scaleToZeroPlugin.enabled (default true
— the plugin is zero-cost when no PSQLCluster opts in).Source URL is annotated for renovate tracking:
source: https://github.com/xataio/cnpg-i-scale-to-zero/releases/download/$VER/manifest.yaml
renovate: datasource=github-releases depName=xataio/cnpg-i-scale-to-zeroPrereq: cert-manager must be installed (provided by the dns-stack in
hops-ops). Without it, the Issuer + Certificate resources won't reconcile
and the plugin Deployment won't have its TLS volumes available.When PSQLClusters opt into scale-to-zero, they add:
metadata.annotations:
xata.io/scale-to-zero-enabled: "true"
xata.io/scale-to-zero-inactivity-minutes: "10"
spec.plugins:
- name: cnpg-i-scale-to-zero.xata.ioImplements [[tasks/psql-stack-cnpg]]
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- docs/test: refresh README, examples, and render tests for CNPG pivot (phase 5)
- README rewritten: CNPG architecture, three-stage journey (EBS-only →
+LVM CoW → +Mayastor HA), full Spec Reference table, prereq notes
(cert-manager via cert-manager-stack; node prep deferred to phase 3b) - examples refreshed:
- minimal: just clusterName, EBS-only baseline
- standard: full production posture (NodePool sub-pools, Mayastor +
LVM + EBS, S2Z plugin, Atlas) - local: dev cluster with LVM CoW only (no Mayastor since replication
needs >1 node, no NodePool, default Helm provider config)
- tests/test-render/main.k: rewritten a...
v0.6.0
What's changed in v0.6.0
-
feat(deps): update crossplane-contrib/function-auto-ready docker tag to v0.6.4 (#9) (by @renovate[bot])
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
See full diff: v0.5.0...v0.6.0
v0.5.0
What's changed in v0.5.0
-
feat(deps): update crossplane-contrib/function-auto-ready docker tag to v0.6.3 (#8) (by @renovate[bot])
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
See full diff: v0.4.0...v0.5.0
v0.4.0
What's changed in v0.4.0
-
chore(deps): update unbounded-tech/workflows-crossplane action to v2.18.0 (#5) (by @renovate[bot])
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
-
chore(deps): update unbounded-tech/workflows-crossplane action to v2.20.0 (#6) (by @renovate[bot])
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
-
feat(deps): update crossplane-contrib/function-auto-ready docker tag to v0.6.2 (#7) (by @renovate[bot])
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
See full diff: v0.3.0...v0.4.0
v0.3.0
What's changed in v0.3.0
-
chore(deps): update unbounded-tech/workflows-crossplane action to v2.16.0 (#2) (by @renovate[bot])
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
-
chore(deps): update unbounded-tech/workflows-crossplane action to v2.17.0 (#4) (by @renovate[bot])
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
-
feat: psql -> psql-stack, kind: PSQLStack, api: hops.ops.com.ai (by @patrickleet)
-
fix: test updates (by @patrickleet)
-
fix: test updates (by @patrickleet)
See full diff: v0.2.0...v0.3.0
v0.2.0
What's changed in v0.2.0
-
chore: readme (by @patrickleet)
-
feat(deps): update crossplane-contrib/function-auto-ready docker tag to v0.6.1 (#1) (by @renovate[bot])
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
See full diff: v0.1.0...v0.2.0
v0.1.0
What's changed in v0.1.0
-
feat: initial commit (by @patrickleet)
-
chore: pipelines + renovate (by @patrickleet)
-
fix: stackgres chart (by @patrickleet)
-
fix: on version tagger workflow (by @patrickleet)