A CNPG-I plugin that automatically hibernates inactive CloudNativePG clusters to optimize resource usage and reduce costs.
This plugin monitors PostgreSQL database activity and automatically scales clusters down to zero replicas when they've been inactive for a configurable period. It injects a monitoring sidecar into all pods of the PostgreSQL cluster. Only the primary pod actively monitors database connections and manages hibernation, while replica pods run the sidecar in passive mode until promoted to primary.
- Sidecar Injection: Automatically adds a monitoring sidecar to all PostgreSQL pods in the cluster
- Primary-Only Monitoring: Only the primary pod actively monitors database connections and query activity
- Passive Replicas: Replica pods run the sidecar container but remain in passive mode (no monitoring)
- Automatic Hibernation: When the cluster is inactive for the configured duration, the primary sidecar sets the hibernation annotation
- Scheduled Backup Management: The primary pod automatically pauses scheduled backups when the cluster is hibernated to prevent backup failures
- Switchover Handling: During switchovers, the new primary automatically takes over monitoring duties while the old primary becomes passive
For detailed installation instructions, see INSTALL.md.
Quick start:
kubectl apply -f manifest.yamlThe plugin consists of two container images:
- Plugin:
ghcr.io/xataio/cnpg-i-scale-to-zero - Sidecar:
ghcr.io/xataio/cnpg-i-scale-to-zero-sidecar
We publish different image tags for different use cases:
dev: local docker images built usingmake docker-build-dev
main: Latest development build from the main branchmain-<sha>: Specific commit builds from main branch
latest: Latest stable releasev1.0.0,v1.1.0, etc.: Specific version releases
Enable scale-to-zero for a PostgreSQL cluster by adding the plugin and configuration annotations:
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: my-cluster
annotations:
xata.io/scale-to-zero-enabled: "true"
xata.io/scale-to-zero-inactivity-minutes: "10"
spec:
instances: 3
enableSuperuserAccess: true
plugins:
- name: cnpg-i-scale-to-zero.xata.io
storage:
size: 1GiThe plugin behavior is configured through cluster annotations:
xata.io/scale-to-zero-enabled: Set to"true"to enable scale-to-zero functionalityxata.io/scale-to-zero-inactivity-minutes: Sets the inactivity threshold in minutes before hibernation (default: 30 minutes)
The plugin automatically manages the cnpg.io/hibernation annotation to trigger cluster hibernation and pauses any associated scheduled backups to prevent backup failures on hibernated clusters.
See the cluster example for a complete configuration.
Important: Each cluster that uses scale-to-zero functionality requires specific RBAC permissions for the sidecar to update cluster resources and manage scheduled backups.
Create the required RBAC using the template:
# Copy the RBAC template
curl -O https://raw.githubusercontent.com/xataio/cnpg-i-scale-to-zero/main/doc/examples/rbac-template.yaml
# Edit the template to replace CLUSTER_NAME and NAMESPACE
sed -i 's/CLUSTER_NAME/my-cluster/g; s/NAMESPACE/default/g' rbac-template.yaml
# Apply the RBAC configuration
kubectl apply -f rbac-template.yamlOr see the RBAC template for manual customization.
The plugin allows you to configure resource requests and limits for the injected sidecar containers through environment variables in the plugin deployment. This enables you to tune resource allocation based on your cluster requirements.
Default Sidecar Resources:
- CPU Request:
50m(0.05 cores) - CPU Limit:
200m(0.2 cores) - Memory Request:
64Mi - Memory Limit:
64Mi
Override via Environment Variables:
You can override these defaults by modifying the plugin deployment manifest before applying it:
# In manifest.yaml, find the deployment and modify the env section:
env:
- name: LOG_LEVEL
value: info
- name: SIDECAR_CPU_REQUEST
value: "100m"
- name: SIDECAR_CPU_LIMIT
value: "500m"
- name: SIDECAR_MEMORY_REQUEST
value: "128Mi"
- name: SIDECAR_MEMORY_LIMIT
value: "128Mi"Override at Runtime:
You can also update resource configuration after deployment using kubectl:
# Update sidecar resource configuration
kubectl set env deployment/scale-to-zero -n cnpg-system \
SIDECAR_CPU_REQUEST=100m \
SIDECAR_CPU_LIMIT=500m \
SIDECAR_MEMORY_REQUEST=128Mi \
SIDECAR_MEMORY_LIMIT=128Mi
# Restart the plugin to apply changes
kubectl rollout restart deployment/scale-to-zero -n cnpg-systemConfigMap Override:
For environment-specific configurations, you can create a ConfigMap:
apiVersion: v1
kind: ConfigMap
metadata:
name: scale-to-zero-resource-overrides
namespace: cnpg-system
data:
SIDECAR_CPU_REQUEST: "200m"
SIDECAR_MEMORY_LIMIT: "512Mi"
---
# Then reference it in the deployment by adding to envFrom:
envFrom:
- configMapRef:
name: scale-to-zero-resource-overrides
optional: trueThese resource configurations apply to all sidecar containers injected by the plugin across all clusters.
The plugin provides logging to help monitor its operation:
- Sidecar injection events are logged during pod creation
- Activity monitoring status is logged at each check interval (primary pod only)
- Primary/replica role transitions are logged when pods change status
- Hibernation events are logged when clusters are scaled down
- Scheduled backup pause operations are logged
You can view the plugin logs using:
kubectl logs -n cnpg-system deployment/cnpg-i-scale-to-zero-pluginAnd monitor the sidecar logs in the PostgreSQL pods:
# View logs from the primary pod's sidecar (active monitoring)
kubectl logs <primary-pod-name> -c scale-to-zero
# View logs from replica pods' sidecars (passive mode)
kubectl logs <replica-pod-name> -c scale-to-zeroNote: Primary pod sidecars will show active monitoring logs, while replica pod sidecars will show minimal passive mode logs.
For local development and building from source:
# Build binaries
make build
# Build Docker images
make docker-build-dev
# Run tests and linting
make test
make lint
# Local development with kind
make kind-deploy-devThis plugin uses the pluginhelper from cnpg-i-machinery to simplify the plugin's implementation.
For additional details on the plugin implementation, refer to the development documentation.
Currently, the plugin only monitors database activity on the primary instance. This means:
- Read-only workloads on replicas are not tracked - If your application connects directly to replica instances for read queries, this activity will not prevent hibernation
- Replica-only traffic - Clusters with active read traffic exclusively on replicas may be hibernated despite being in use
- Connection pooling to replicas - Applications using connection poolers that direct read traffic to replicas will not be detected as active
Workaround: Ensure critical read workloads also maintain at least one connection to the primary instance, or configure longer inactivity periods to account for replica-only usage patterns.
Future Enhancement: Replica activity monitoring may be added in future versions to provide more comprehensive activity detection across the entire cluster.
