mcpField
C
cnpg-database

cnpg-database

github.com/ionfuryCloud & DevOps2550 installsUpdated today
Repository

About cnpg-database

cnpg-database is an operational skill for managing CloudNativePG databases in Kubernetes, aimed at people maintaining clusters and configuring app databases. It covers shared and dedicated clusters, credential replication, monitoring, and troubleshooting workflows.

Key features

  1. 01Shared vs. dedicated cluster guidance
  2. 02Steps to add an app database
  3. 03Credential replication and network policies
  4. 04Prometheus monitoring and alerts
  5. 05Connection checks and troubleshooting

Use cases

  1. 01Create a shared-cluster database for an app
  2. 02Deploy a dedicated cluster for extensions or isolation
  3. 03Troubleshoot app connectivity or credential issues

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/ionfury/homelab --skill cnpg-database

After installing, type/cnpg-databasein Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

tests.yaml
references/
cluster-reference.md
credentials.md
scripts/
check-connection.sh

Details

From the project README

CNPG Database Management

Architecture Overview

All clusters live in the database namespace. The shared platform cluster (platform-0/1/2) uses spec.managed.roles + Database CRDs per app, with PgBouncer pooler at platform-pooler-rw.database.svc. Dedicated clusters (e.g., Immich) bootstrap their own DB and owner via initdb. In both cases, credentials are replicated via kubernetes-replicator to the consumer app namespace.

Decision Tree: Shared vs Dedicated Cluster

Standard workload, no special extensions → shared cluster (platform-pooler-rw.database.svc) Needs custom extensions (vector, PostGIS) or isolation → dedicated cluster with custom imageName Unclear → start with shared, migrate if needed


Key Files (Shared Cluster)

Location: kubernetes/platform/config/database/

FilePurpose
cluster.yamlCNPG Cluster CR with spec.managed.roles
databases.yamlDatabase CRDs (one per app database)
role-secrets.yamlPer-role password secrets (secret-generator + replicator)
pooler.yamlPgBouncer Pooler (platform-pooler-rw)
superuser-secret.yamlAuto-generated superuser password (database ns only)
prometheus-rules.yamlCNPG-specific PrometheusRules

For manifest examples, see references/cluster-reference.md.


Workflow: Add a Database for a New App (Shared Cluster)

Steps 1-3 edit files in kubernetes/platform/config/database/. Steps 4-5 are in the app's cluster config.

Step 1: Add managed role to cluster.yaml spec.managed.roles. Template: see references/cluster-reference.md.

Step 2: Create role password secret in role-secrets.yaml. Template: see references/credentials.md.

Step 3: Create Database CRD in databases.yaml. Template: see references/cluster-reference.md.

Note: Apps with multiple databases (sonarr-main, sonarr-log) share one role; create separate Database CRs with the same owner.

Step 4: Create credential replica in kubernetes/clusters/<cluster>/config/<app>/. Template: see references/credentials.md.

Step 5: Add network policy access label access.network-policy.homelab/postgres: "true" to the namespace entry in kubernetes/platform/namespaces.yaml.

Step 6: Register the credential replica in the app's kustomization.yaml.

For credential chain diagrams, see references/credentials.md.


Workflow: Create a Dedicated CNPG Cluster

Use when the app needs custom PostgreSQL extensions or performance/data isolation.

Step 1: Define the Cluster at kubernetes/clusters/<cluster>/config/<app>/<app>-cluster.yaml. Set inheritedMetadata to allow replication of the auto-generated app secret. For a full manifest example, see references/cluster-reference.md.

Key differences vs shared cluster:

FeatureSharedDedicated
Locationkubernetes/platform/config/database/kubernetes/clusters/<cluster>/config/<app>/
ImageStandard PostgreSQLCustom image with extensions
Role managementspec.managed.roles + Database CRDsbootstrap.initdb creates DB and owner
Credential source<app>-role-password (secret-generator)<app>-database-app (CNPG auto-generated)
inheritedMetadataNot neededRequired for secret replication

Step 2: Replicate app credentials to the consumer namespace. CNPG auto-generates <cluster-name>-app in database. The inheritedMetadata annotations enable replication. Template: see references/credentials.md.

Real example: kubernetes/clusters/live/config/immich/database-secret-replication.yaml

Step 3: Add the access.network-policy.homelab/postgres: "true" label to the app namespace and register all files in kustomization.yaml.


Monitoring

Both Cluster and Pooler set monitoring.enablePodMonitor: true — Prometheus discovers them automatically. No manual ServiceMonitor needed.

CNPG alerts are in kubernetes/platform/config/database/prometheus-rules.yaml:

AlertConditionSeverity
CNPGClusterNotHealthycnpg_pg_replication_streaming == 0critical
CNPGClusterHighConnectionsConnection usage > 80% of max_connectionswarning
CNPGInstanceNotReadyReplica WAL receiver downcritical

Key metrics: cnpg_pg_replication_streaming, cnpg_pg_stat_activity_count, cnpg_pg_settings_setting{name="max_connections"}, cnpg_pg_replication_is_wal_receiver_up.


Debugging

Use scripts/check-connection.sh <cluster> <app-namespace> [app-name] for structured health checks.

Common issues:

SymptomCauseFix
Pods PendingNo PVs availableCheck StorageClass fast exists, Longhorn healthy
CrashLoopBackOffOOM or bad configCheck kubectl logs, increase memory limits
App can't connectNetwork policy missingAdd access.network-policy.homelab/postgres: "true"
App can't connectSecret not replicatedCheck replication annotations on source secret
Secret empty after replicationSource namespace wrongVerify replicate-from points to correct <ns>/<name>
Extension not foundWrong imageVerify imageName includes the extension
Database not createdDatabase CRD missingAdd Database CR to databases.yaml
Role not createdMissing from managed.rolesAdd role entry to cluster.yaml
Role password mismatchSecret not regeneratedDelete the role-password secret; secret-generator recreates it

Manual connectivity test: kubectl run -n <app-ns> pg-test --rm -it --image=postgres:17 -- psql "postgresql://user:[email protected]:5432/dbname"


Cross-References

DocumentRelevance
references/cluster-reference.mdCluster CRD fields and full manifest examples
references/credentials.mdCredential chain diagrams and secret templates
scripts/check-connection.shStructured health check commands
secrets skillsecret-generator, ExternalSecret, and replication patterns
deploy-app skillEnd-to-end deployment including database setup
kubernetes/platform/config/CLAUDE.mdConfig subsystem and CRD dependency patterns

Comments

Markdown supported