From b8bd7eda9330e71216a756b7517cf8294c7dd876 Mon Sep 17 00:00:00 2001 From: Mitchell Murphy Date: Sun, 7 Jun 2026 17:20:57 -0400 Subject: [PATCH] docs(pooler): add documentation for operator-generated PgBouncer config Signed-off-by: Mitchell Murphy --- docs/pgbouncer-generated-config.md | 133 +++++++++++++++++++++++++++++ mkdocs.yml | 1 + 2 files changed, 134 insertions(+) create mode 100644 docs/pgbouncer-generated-config.md diff --git a/docs/pgbouncer-generated-config.md b/docs/pgbouncer-generated-config.md new file mode 100644 index 000000000..d2c670689 --- /dev/null +++ b/docs/pgbouncer-generated-config.md @@ -0,0 +1,133 @@ +

Operator-generated PgBouncer config (Helm)

+ +By default the connection pooler relies on the PgBouncer image's entrypoint to render `pgbouncer.ini` from environment variables (this is what the bundled `ghcr.io/zalando/postgres-operator/pgbouncer` image does). Some images — for example the **Chainguard FIPS PgBouncer** image — ship no such entrypoint. + +When `connection_pooler_generate_config` is enabled, the operator renders the config itself instead of relying on the image. For every pooler it: + +- renders `pgbouncer.ini` and stores it in a ConfigMap named `-config` (e.g. `acid-minimal-cluster-pooler-config`); +- mounts that ConfigMap into the pooler container at `connection_pooler_config_path` using a `subPath`; +- overrides the container `command`/`args` (when set) so PgBouncer reads the mounted file; +- stamps the pod template with an `acid.zalan.do/pgbouncer-config-checksum` annotation, so the pooler restarts automatically when the rendered config changes. + +The feature is **opt-in**; with the default `connection_pooler_generate_config: false` nothing changes for existing clusters. + +## 1. Configure the operator via the Helm chart + +These settings are operator-wide defaults and live under `configConnectionPooler` in the chart's `values.yaml`. + +```yaml +configConnectionPooler: + # Point the pooler at an image whose entrypoint does NOT render pgbouncer.ini. + # Replace with your actual image reference. + connection_pooler_image: "cgr.dev/chainguard/pgbouncer-fips:latest" + + # Let the operator render and own pgbouncer.ini. + connection_pooler_generate_config: true + + # Optional: override the container entrypoint. Leave unset to keep the image's + # own entrypoint. Set it when the image has no entrypoint that starts pgbouncer. + connection_pooler_command: + - "pgbouncer" + # Args are applied only when generate_config is true. The default already points + # pgbouncer at the mounted config file, so you usually don't need to change it. + connection_pooler_args: + - "/etc/pgbouncer/pgbouncer.ini" + + # Written into the generated pgbouncer.ini. + connection_pooler_auth_type: "scram-sha-256" + # Where the ConfigMap is mounted (and where args/command should point). + connection_pooler_config_path: "/etc/pgbouncer/pgbouncer.ini" +``` + +Install or upgrade the operator with these values: + +```bash +helm upgrade --install postgres-operator ./charts/postgres-operator \ + --namespace postgres-operator --create-namespace \ + -f values-pooler.yaml +``` + +Or set individual values inline: + +```bash +helm upgrade --install postgres-operator ./charts/postgres-operator \ + --namespace postgres-operator --create-namespace \ + --set configConnectionPooler.connection_pooler_generate_config=true \ + --set configConnectionPooler.connection_pooler_image="cgr.dev/chainguard/pgbouncer-fips:latest" +``` + +| Value (under `configConnectionPooler`) | Default | Purpose | +|---|---|---| +| `connection_pooler_generate_config` | `false` | Master switch — render `pgbouncer.ini` into an operator-owned ConfigMap. | +| `connection_pooler_command` | _(unset)_ | Container `command` override; unset keeps the image entrypoint. Applied only when generating. | +| `connection_pooler_args` | `["/etc/pgbouncer/pgbouncer.ini"]` | Container `args`; applied only when generating. | +| `connection_pooler_auth_type` | `scram-sha-256` | `auth_type` written into the rendered config. | +| `connection_pooler_config_path` | `/etc/pgbouncer/pgbouncer.ini` | Mount path of the generated config. | + +## 2. Enable the pooler on a Postgres cluster + +The operator settings above only take effect for clusters that actually run a pooler. Enable it in the `postgresql` manifest: + +```yaml +apiVersion: "acid.zalan.do/v1" +kind: postgresql +metadata: + name: acid-minimal-cluster + namespace: default +spec: + teamId: "acid" + postgresql: + version: "17" + numberOfInstances: 2 + volume: + size: 1Gi + + # Run a master connection pooler for this cluster. + enableConnectionPooler: true + # Optionally also pool replica connections: + # enableReplicaConnectionPooler: true + + # Per-cluster pooler overrides are optional; defaults come from the operator config. + connectionPooler: + numberOfInstances: 2 + mode: "transaction" +``` + +## 3. Verify + +```bash +# The operator-owned config map for the master pooler: +kubectl get configmap acid-minimal-cluster-pooler-config -o yaml + +# Inspect the rendered pgbouncer.ini: +kubectl get configmap acid-minimal-cluster-pooler-config \ + -o jsonpath='{.data.pgbouncer\.ini}' + +# Confirm the pooler pod mounts it and carries the checksum annotation: +kubectl get pod -l connection-pooler=acid-minimal-cluster-pooler \ + -o jsonpath='{.items[0].metadata.annotations.acid\.zalan\.do/pgbouncer-config-checksum}' +``` + +A rendered config looks roughly like: + +```ini +[databases] +* = host=acid-minimal-cluster port=5432 + +[pgbouncer] +pool_mode = transaction +auth_type = scram-sha-256 +auth_file = /etc/pgbouncer/userlist.txt +auth_query = SELECT * FROM pooler.user_lookup($1) +server_tls_sslmode = require +default_pool_size = 15 +max_db_connections = 30 +``` + +When the cluster has TLS configured (`spec.tls`), the operator additionally renders `client_tls_sslmode`, `client_tls_key_file`, and `client_tls_cert_file`. + +## Notes + +- `connection_pooler_command` and `connection_pooler_args` are applied **only** when `connection_pooler_generate_config` is `true`. With generation off, the image entrypoint runs unchanged. +- Changing any input that affects the rendered config (mode, auth type, sizes, TLS) updates the ConfigMap and changes the checksum annotation, which rolls the pooler pods automatically. +- The same parameters are available on the `OperatorConfiguration` CRD as `connection_pooler_generate_config`, `connection_pooler_command`, `connection_pooler_args`, `connection_pooler_auth_type`, and `connection_pooler_config_path`. diff --git a/mkdocs.yml b/mkdocs.yml index b8e8c3e04..93c743375 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -8,6 +8,7 @@ nav: - Postgres Operator UI: 'operator-ui.md' - Admin guide: 'administrator.md' - User guide: 'user.md' + - PgBouncer generated config: 'pgbouncer-generated-config.md' - Developer guide: 'developer.md' - Reference: - Config parameters: 'reference/operator_parameters.md'