Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
9787922
feat(config): add connection_pooler generate-config fields
mkm29 Jun 5, 2026
c49aac8
test(config): cover ConfigPath and Command overrides
mkm29 Jun 5, 2026
bf0aa1e
feat(crd): mirror connection_pooler generate-config fields in Operato…
mkm29 Jun 5, 2026
1383829
style(crd): gofmt connection pooler config fields
mkm29 Jun 5, 2026
ac8668a
refactor(pooler): extract connectionPoolerSizes helper
mkm29 Jun 5, 2026
db68903
docs(pooler): fix godoc placement after sizes extraction
mkm29 Jun 5, 2026
3dabf6c
feat(pooler): render pgbouncer.ini, checksum, and config map
mkm29 Jun 5, 2026
be3fbda
style(pooler): use acid.zalan.do domain for config checksum annotation
mkm29 Jun 5, 2026
8641fbd
feat(pooler): mount generated config and override command/args
mkm29 Jun 5, 2026
c5e0b43
refactor(pooler): extract connectionPoolerConfigMapName helper
mkm29 Jun 5, 2026
e79c7d3
feat(pooler): create/sync/delete generated config map in lifecycle
mkm29 Jun 5, 2026
c6d0476
test(pooler): cover config map update-on-drift branch
mkm29 Jun 5, 2026
3d97c71
docs(pooler): document and expose generate-config parameters
mkm29 Jun 5, 2026
4557229
docs(pooler): align values.yaml args with manifest and tidy param docs
mkm29 Jun 5, 2026
964fc73
test(pooler): refactor connection pooler config tests to use assert p…
mkm29 Jun 7, 2026
b8bd7ed
docs(pooler): add documentation for operator-generated PgBouncer config
mkm29 Jun 7, 2026
4af7b5a
Merge branch 'master' into feat/enhanced-pooler-config
mkm29 Jun 25, 2026
67046ef
Merge branch 'master' into feat/enhanced-pooler-config
mkm29 Jun 26, 2026
8781170
Merge branch 'master' into feat/enhanced-pooler-config
FxKu Jun 29, 2026
b11f5e5
fix(pooler): resolved duplicate fields in ConnectionPoolerConfigurati…
mkm29 Jun 29, 2026
d762e70
Merge branch 'master' into feat/enhanced-pooler-config
mkm29 Jul 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions charts/postgres-operator/crds/operatorconfigurations.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -942,6 +942,25 @@ spec:
super_username:
default: postgres
type: string
pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$'
connection_pooler_generate_config:
type: boolean
default: false
connection_pooler_command:
type: array
items:
type: string
connection_pooler_args:
type: array
items:
type: string
connection_pooler_auth_type:
type: string
default: "scram-sha-256"
connection_pooler_config_path:
type: string
default: "/etc/pgbouncer/pgbouncer.ini"
patroni:
type: object
workers:
default: 8
Expand Down
9 changes: 9 additions & 0 deletions charts/postgres-operator/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,15 @@ configConnectionPooler:
connection_pooler_default_memory_request: 100Mi
connection_pooler_default_cpu_limit: "1"
connection_pooler_default_memory_limit: 100Mi
# whether the operator should generate the pgbouncer.ini config map and
# override the pooler container command/args (needed for images without an
# entrypoint that renders the config, e.g. the Chainguard FIPS pgbouncer image)
connection_pooler_generate_config: false
# connection_pooler_command: []
# connection_pooler_args:
# - "/etc/pgbouncer/pgbouncer.ini"
connection_pooler_auth_type: "scram-sha-256"
connection_pooler_config_path: "/etc/pgbouncer/pgbouncer.ini"

configPatroni:
# enable Patroni DCS failsafe_mode feature
Expand Down
133 changes: 133 additions & 0 deletions docs/pgbouncer-generated-config.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
<h1>Operator-generated PgBouncer config (Helm)</h1>

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 `<pooler>-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`.
24 changes: 24 additions & 0 deletions docs/reference/operator_parameters.md
Original file line number Diff line number Diff line change
Expand Up @@ -1105,3 +1105,27 @@ operator being able to provide some reasonable defaults.
**connection_pooler_default_cpu_limit**
**connection_pooler_default_memory_limit**
Default resource configuration for connection pooler deployment.

* **connection_pooler_generate_config**
When `true`, the operator renders a `pgbouncer.ini` into an operator-owned
ConfigMap, mounts it into the pooler pod, and overrides the container
command/args. Use for pgbouncer images that do not ship an entrypoint that
renders the config (e.g. FIPS/distroless images). The default `false`
preserves the stock behavior of relying on the image entrypoint.

* **connection_pooler_command**
Container `command` override applied only when `connection_pooler_generate_config`
is enabled. Empty (default) keeps the image entrypoint.

* **connection_pooler_args**
Container `args` applied only when `connection_pooler_generate_config` is
enabled. The default `["/etc/pgbouncer/pgbouncer.ini"]` points pgbouncer at the
mounted config.

* **connection_pooler_auth_type**
`auth_type` written into the generated `pgbouncer.ini`. The default is
`scram-sha-256`.

* **connection_pooler_config_path**
Mount path of the generated `pgbouncer.ini` inside the pooler container. The
default is `/etc/pgbouncer/pgbouncer.ini`.
Loading
Loading