CloudNativePG
Use the cnpg provider when PostgreSQL runs under the CloudNativePG operator. Set
type = "cnpg" and name the Cluster. The collector asks Kubernetes which pod is the primary, which
pods are standbys, and where their metrics ports are. It keeps that answer current, so a failover
requires no config change and does not lose history.
The chart, the namespace, secrets, and the install command work as described on the
Kubernetes page. That page also works against a CloudNativePG cluster
with type = "self_hosted" pointed at the -rw service. The cnpg provider has three differences:
- Failover keeps the same component. The component’s identity is the namespace and Cluster name, so when CloudNativePG promotes a standby, the collector picks up the new primary on its next discovery pass and history continues under the same component.
- It scrapes every instance rather than only the primary. Each PostgreSQL pod exposes metrics on port 9187 through the operator’s instance manager, and the collector reads all of them, so per-standby replication lag arrives as its own series.
- It leaves out PgBouncer pods. Pods created by a
Poolercarry the samecnpg.io/clusterlabel as the database pods. The provider filters oncnpg.io/podRole=instance, so those pods are not scraped.
Before you start
Section titled “Before you start”The requirements in Before you start on the Kubernetes page apply here, along with the following:
- The collector runs inside the same Kubernetes cluster as the CloudNativePG Cluster. It reaches the Kubernetes API with its own ServiceAccount token and dials pod IPs directly for the metrics scrape. Neither works from outside.
- A read-only Role in the namespace that holds the Cluster. The chart creates it when you ask. See Kubernetes read access.
pg_stat_statementsloaded through the Cluster spec. See pg_stat_statements.- The same
dbg_readonlylogin as everywhere else. See Grants.
Kubernetes read access
Section titled “Kubernetes read access”The provider reads three kinds of object: the Cluster itself, to learn the current primary and
whether monitoring is served over TLS; the Cluster’s pods, to find instance addresses; and pod
metrics. It gets three verbs, get, list and watch. No writes, no exec, and no access to
Secrets. Nothing the collector is granted can change a database or a Kubernetes object.
The Role the chart creates allows reading more than the provider uses. With the same three verbs it
also covers backups, scheduledbackups, poolers, databases, publications,
subscriptions, failoverquorums and imagecatalogs, Barman objectstores, and
persistentvolumeclaims.
The chart renders this when rbac.create is on. The only decision is where to bind it:
rbac: create: true scope: namespaced namespaces: - prod-db # the namespace that HOLDS the ClusterWithout rbac.create, discovery uses metrics only.
scope: cluster binds the same permissions across every namespace. Use it only when you discover
Clusters across the whole cluster.
Pod CPU, memory and disk
Section titled “Pod CPU, memory and disk”rbac.nodeMetrics is on by default and is separate from scope. The collector reads each
database pod’s CPU, memory, and volume usage from the kubelet on the node that runs it. The objects
that authorize that read, nodes, nodes/stats, and nodes/pods, are cluster scoped, so this
binding is always a ClusterRoleBinding, whatever scope says. It reads node statistics and grants
nothing on any database object.
Set it to false and you lose those three metrics for your database pods. The collector checks the
grant at startup and skips the pipeline when it is missing. Nothing else is affected.
Choosing kubernetes.mode
Section titled “Choosing kubernetes.mode”| Mode | What it does | Use it when |
|---|---|---|
auto (default) | Tries the API. Full mode if it can read, metrics-only if it cannot. | You want an install that never fails on permissions |
enabled | Requires the API. Fails with an error if the Role is missing. | You want to know the moment the Role is wrong |
disabled | Never calls the API. No Kubernetes permissions needed. | You cannot grant read access at all |
In auto mode a missing binding does not fail the install. The collector runs and reports fewer
metrics, with no error. If you have granted the Role and want proof it works, set
mode = "enabled" and read the logs.
pg_stat_statements under CloudNativePG
Section titled “pg_stat_statements under CloudNativePG”Do not run ALTER SYSTEM on an operator-managed cluster. Declare the library in the Cluster
spec and CloudNativePG restarts the instances for you:
apiVersion: postgresql.cnpg.io/v1kind: Clustermetadata: name: app-db namespace: prod-dbspec: postgresql: shared_preload_libraries: - pg_stat_statements parameters: shared_buffers: 256MBConnect to each database you will list under databases:
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;Adding a library to shared_preload_libraries triggers a rolling restart of the instances. Plan
it like any restart. It is the only disruptive step in this install.
Grants
Section titled “Grants”The provider adds no SQL requirement of its own. Create dbg_readonly exactly as in
Prepare PostgreSQL, connected to the primary
through the -rw service. Repeat the per-database USAGE and SELECT grants in every database
you list.
Here, members come from the Kubernetes API, so the topology stays correct without pg_monitor. On
the generic Kubernetes path, a missing pg_monitor grant collapses a cluster of three nodes to one
node, because members are discovered through pg_stat_replication. pg_monitor is still required: the collector reads
pg_stat_activity and pg_stat_statements through it, and every query-level feature rests on
that.
Install
Section titled “Install”How the collector connects
Section titled “How the collector connects”SQL goes to the -rw service only. Each standby is scraped on its metrics port and never gets a
SQL connection.
CloudNativePG issues one server certificate per
Cluster, shared by every instance, whose names cover the -rw, -ro, and -r services and
nothing else: no pod names or IP addresses. The collector verifies certificates by default, so a
SQL connection to a pod can never verify. A metrics scrape can dial a pod IP while checking the
certificate against the -rw name, so that is how per-instance data is read.
The primary is the SQL source and one metrics target. Each standby is a metrics target only. In the app, a standby shows as a member you cannot run a query against. That is expected.
Point host at the short service name when the collector runs in the same namespace, or the
fully qualified one otherwise. Both are on the certificate:
host = "app-db-rw" # same namespacehost = "app-db-rw.prod-db.svc.cluster.local" # anywhere in the clusterMetrics on 9187 are plain HTTP unless the Cluster sets .spec.monitoring.tls.enabled. When it
does, the collector switches the scrape to TLS and verifies against the Cluster CA on its own. You
do not configure that.
Run the install
Section titled “Run the install”collector.toml, one [[component]] per Cluster:
[dbgorilla]agent_id = "<agent id from the app>"tenant_id = "<tenant id from the app>"secret = { env = "DBG_SERVER_SECRET" }
[topology]interval = "60s"
[commands]enabled = trueallowed = ["explain", "collect_statistics"] # see https://www.dbgorilla.com/docs/reference/collector-commands/#database-commands
[[component]]name = "prod-cnpg"engine = "postgres"
[component.provider]type = "cnpg"namespace = "prod-db" # requiredcluster = "app-db" # required
[component.provider.kubernetes]mode = "auto"
[component.provider.metrics]port = 9187
[component.auth]method = "password"user = "dbg_readonly"password = { env = "APP_DB_PASSWORD" }
[component.connect]host = "app-db-rw"port = 5432ssl_mode = "verify-full"databases = ["app"]values.yaml:
rbac: create: true scope: namespaced namespaces: - prod-db
secrets: serverSecret: "<secret from the app>" databasePasswords: APP_DB_PASSWORD: "<the dbg_readonly password>"Then:
helm install dbg-collector oci://dbgorillapublic.azurecr.io/charts/dbg-collector \ --namespace prod-db \ --values ./values.yaml \ --set-file config.inline=./collector.tomlThis config has no ca_cert and no mounted CA, unlike the Kubernetes page. SQL goes to the -rw
name on the Cluster certificate, and the metrics scrape carries its own trust. The config also
omits a node_exporter block because the cnpg provider has none: there is no host to probe.
Several Clusters, one collector
Section titled “Several Clusters, one collector”Add a [[component]] block per Cluster, each with its own namespace and cluster, and list every
namespace under rbac.namespaces. One stanza is always one Cluster. Discovery runs inside a single
namespace, so that a component’s identity is settled before it starts.
Check it is working
Section titled “Check it is working”Follow Check it worked for CloudNativePG.
Upgrade
Section titled “Upgrade”See Upgrading and removing in Manage collectors.
Remove
Section titled “Remove”helm uninstall and what it removes are under
Upgrading and removing in Manage collectors.
To manage this install from Terraform, see Deploying from Terraform.