Skip to content

feat: support CloudNativePG Cluster (hibernate) in the Kubernetes provider #943

Description

@antoinemichea

Describe the provider

This is not strictly a new provider, but an extension of the existing Kubernetes provider to handle CloudNativePG (CNPG) Cluster resources (postgresql.cnpg.io/v1) as a new kind alongside deployment and statefulset.

CNPG ships with a built-in declarative hibernation mechanism, triggered by an annotation on the Cluster CR:

  • cnpg.io/hibernation: on -> the operator scales the workload down, removes the underlying StatefulSet, but keeps the PVCs intact.
  • cnpg.io/hibernation: off (or annotation removed) -> the operator rebuilds the StatefulSet and the cluster comes back online.

This maps very cleanly onto Sablier's InstanceStop / InstanceStart semantics, so a small extension to the Kubernetes provider would unlock CNPG-backed workloads.

Why this matters (use case)

Our typical workload (Opencell) is a stack of three pieces deployed in the same cluster:

  • an Opencell StatefulSet
  • a Keycloak Deployment
  • a CNPG Cluster for the database

We'd like to put all three in the same sablier.group=opencell so that hitting the Traefik ingress wakes the whole stack up, and inactivity hibernates the whole stack. Today the first two are covered out of the box; only the CNPG Cluster is missing. Note that scaling the operator-managed StatefulSet directly is not viable (the operator reconciles it back), which is why going through the official hibernation annotation is the right path.

Does the provider provide the following APIs?

API Yes No I don't know
Start an instance x
Stop an instance x
Get info about an instance x
Listening for external events happening x
  • Start: PATCH the Cluster CR to set cnpg.io/hibernation: off (or remove the annotation).
  • Stop: PATCH the Cluster CR to set cnpg.io/hibernation: on.
  • Inspect: read spec.instances, status.readyInstances and the hibernation annotation to compute Ready / Starting / Stopped.
  • Events: dynamic informer on clusters.postgresql.cnpg.io to emit the stopped event when hibernation transitions to on.

Does the provider have a Go API SDK?

Two options, both viable:

  • Typed client: https://github.com/cloudnative-pg/cloudnative-pg (api/v1 package). Cleanest, but adds a non-trivial dependency (pulls controller-runtime transitively).
  • Dynamic client from client-go (dynamic.Interface). Already available transitively in Sablier, no new dependency. A bit less ergonomic but perfectly sufficient for the surface we need (annotation patch + read a couple of status fields + informer).

Our preference would be the dynamic client to keep the dependency footprint minimal, but happy to align with whatever the maintainers prefer.

Can the provider be started locally?

Yes. CNPG is installable in any local cluster (kind, k3s, minikube) via a single manifest:

kubectl apply --server-side -f \
  https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/main/releases/cnpg-1.x.y.yaml

This makes it easy to wire up testcontainers-based integration tests in the same spirit as the existing Kubernetes provider tests.

Proposed shape of the change

Mostly additive, following the existing per-kind file pattern in pkg/provider/kubernetes/:

  • New files: cnpgcluster_inspect.go, cnpgcluster_list.go, cnpgcluster_events.go, cnpgcluster_hibernate.go (+ tests).
  • Small edits to route the new kind in parse_name.go, instance_inspect.go, instance_start.go, instance_stop.go, instance_list.go, instance_events.go, kubernetes.go.
  • New doc page docs/providers/cnpg.md (sibling of the existing provider docs).
  • No change to the sablier.Provider interface, no new CLI flag required.

Rough estimate: ~400-600 LOC including tests.

Additional context

If this is something you'd be open to merging, we'd be glad to do the implementation work and submit a PR. We just wanted to surface the proposal and the design choices first to avoid building something that wouldn't be welcome.

Happy to discuss the design (typed client vs dynamic client, naming of the kind, readiness semantics for multi-instance clusters, etc.) before writing any code.

Thanks for the project!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions