Skip to content

Commit 3c943cb

Browse files
cnp-autobotgithub-actions[bot]
authored andcommitted
Sync EnterpriseDB/cloud-native-postgres product/pg4k/v1.30.0-rc1-next
1 parent 112bea3 commit 3c943cb

39 files changed

Lines changed: 4720 additions & 292 deletions

product_docs/docs/postgres_for_kubernetes/1/backup.mdx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,13 @@ The schedule `"0 0 0 * * *"` triggers a backup every day at midnight
241241
(00:00:00). In Kubernetes CronJobs, the equivalent expression would be `0 0 * * *`,
242242
since seconds are not supported.
243243

244+
!!!warning
245+
246+
The `spec.cluster` field is immutable after creation. To schedule backups
247+
for a different `Cluster`, create a new `ScheduledBackup` resource instead
248+
of updating an existing one.
249+
!!!
250+
244251
### Backup Frequency and RTO
245252

246253
!!!tip Hint

product_docs/docs/postgres_for_kubernetes/1/bootstrap.mdx

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,17 @@ cluster. An error in any of those queries will interrupt the bootstrap phase,
388388
leaving the cluster incomplete and requiring manual intervention.
389389
!!!
390390

391+
!!!note
392+
393+
These queries run with the standard `"$user", public` `search_path`, even
394+
though operator-issued connections otherwise pin a fixed `search_path` for
395+
security reasons.
396+
See [Schema resolution and `search_path` hardening](security.md#schema-resolution-and-search_path-hardening)
397+
for details.
398+
Schema-qualify object references if you need them to be independent of the
399+
`search_path`.
400+
!!!
401+
391402
!!!info Important
392403
Ensure the existence of entries inside the ConfigMaps or Secrets specified
393404
in `postInitSQLRefs`, `postInitTemplateSQLRefs`, and
@@ -647,7 +658,7 @@ file on the source PostgreSQL instance:
647658
host replication streaming_replica all md5
648659
```
649660

650-
The following manifest creates a new PostgreSQL 18.3 cluster,
661+
The following manifest creates a new PostgreSQL 18.4 cluster,
651662
called `target-db`, using the `pg_basebackup` bootstrap method
652663
to clone an external PostgreSQL cluster defined as `source-db`
653664
(in the `externalClusters` array). As you can see, the `source-db`
@@ -662,7 +673,7 @@ metadata:
662673
name: target-db
663674
spec:
664675
instances: 3
665-
imageName: docker.enterprisedb.com/k8s/postgresql:18.3-standard-ubi9
676+
imageName: docker.enterprisedb.com/k8s/postgresql:18.4-standard-ubi9
666677
667678
bootstrap:
668679
pg_basebackup:
@@ -682,7 +693,7 @@ spec:
682693
```
683694

684695
All the requirements must be met for the clone operation to work, including
685-
the same PostgreSQL version (in our case 18.3).
696+
the same PostgreSQL version (in our case 18.4).
686697

687698
#### TLS certificate authentication
688699

@@ -698,7 +709,7 @@ This example can be easily adapted to cover an instance that resides
698709
outside the Kubernetes cluster.
699710
!!!
700711

701-
The manifest defines a new PostgreSQL 18.3 cluster called `cluster-clone-tls`,
712+
The manifest defines a new PostgreSQL 18.4 cluster called `cluster-clone-tls`,
702713
which is bootstrapped using the `pg_basebackup` method from the `cluster-example`
703714
external cluster. The host is identified by the read/write service
704715
in the same cluster, while the `streaming_replica` user is authenticated
@@ -713,7 +724,7 @@ metadata:
713724
name: cluster-clone-tls
714725
spec:
715726
instances: 3
716-
imageName: docker.enterprisedb.com/k8s/postgresql:18.3-standard-ubi9
727+
imageName: docker.enterprisedb.com/k8s/postgresql:18.4-standard-ubi9
717728
718729
bootstrap:
719730
pg_basebackup:

product_docs/docs/postgres_for_kubernetes/1/certificates.mdx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,15 @@ names in user-provided certificates for the `<cluster>-rw` service used for
3939
communication within the cluster.
4040
!!!
4141

42+
!!!note
43+
44+
Beyond the CA-managed certificates listed above, the operator also uses a
45+
self-signed client certificate, generated in memory, to authenticate to the
46+
instance manager's status port. This certificate is not signed by the client
47+
CA: the instance manager trusts it by pinning its public-key fingerprint. See
48+
[Operator-to-instance authentication](security.md#operator-to-instance-authentication).
49+
!!!
50+
4251
## Operator-Managed Mode
4352

4453
By default, the operator automatically generates a single Certificate Authority

product_docs/docs/postgres_for_kubernetes/1/cnpg_i.mdx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,12 @@ TCP gRPC endpoint behind a Service, with **mTLS** for secure communication.
9292
Standalone plugins are discovered dynamically by watching for Services with the
9393
required labels and annotations — no operator restart is needed.
9494
95+
When a standalone plugin's pods are rolled (for example, after upgrading its
96+
image), the operator detects the change through the EndpointSlices backing the
97+
plugin Service and reconciles every cluster using that plugin, so they start
98+
interacting with the new pods promptly instead of waiting for the periodic
99+
resync.
100+
95101
Example Deployment:
96102
97103
```yaml

product_docs/docs/postgres_for_kubernetes/1/connection_pooling.mdx

Lines changed: 192 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,13 @@ spec:
5757
The pooler name can't be the same as any cluster name in the same namespace.
5858
!!!
5959
60+
!!!warning
61+
62+
The `spec.cluster` field is immutable after creation. To point a pooler at
63+
a different `Cluster`, create a new `Pooler` resource instead of updating
64+
an existing one.
65+
!!!
66+
6067
This example creates a `Pooler` resource called `pooler-example-rw`
6168
that's strictly associated with the Postgres `Cluster` resource called
6269
`cluster-example`. It points to the primary, identified by the read/write
@@ -190,15 +197,27 @@ GRANT CONNECT ON DATABASE postgres TO cnp_pooler_pgbouncer;
190197

191198
Create the lookup function for password verification. This function is created
192199
in the `postgres` database with `SECURITY DEFINER` privileges and is used by
193-
PgBouncer’s `auth_query` option:
200+
PgBouncer’s `auth_query` option. Because it runs as the function owner, its
201+
`search_path` is pinned to `pg_catalog, pg_temp` so that the function body
202+
cannot resolve operators or objects through a caller- or
203+
tenant-controlled `search_path`:
194204

195205
```sql
196206
CREATE OR REPLACE FUNCTION public.user_search(uname TEXT)
197207
RETURNS TABLE (usename name, passwd text)
198-
LANGUAGE sql SECURITY DEFINER AS
208+
LANGUAGE sql SECURITY DEFINER
209+
SET search_path = pg_catalog, pg_temp AS
199210
'SELECT usename, passwd FROM pg_catalog.pg_shadow WHERE usename=$1;';
200211
```
201212

213+
!!!note
214+
215+
Clusters created with an earlier version of {{name.ln}} carry a
216+
`user_search` function without the pinned `search_path`. The operator
217+
recreates the function with the `SET search_path` clause automatically
218+
during reconciliation when the cluster is upgraded.
219+
!!!
220+
202221
Restrict and grant permissions on the lookup function:
203222

204223
```sql
@@ -280,10 +299,89 @@ spec:
280299
topologyKey: "kubernetes.io/hostname"
281300
```
282301

283-
#### Custom image and resource limits
302+
#### Resource limits
303+
304+
You can define resource requests and limits by adding a container named
305+
`pgbouncer` to the `template` section:
306+
307+
```yaml
308+
# ...
309+
template:
310+
metadata:
311+
# ...
312+
spec:
313+
containers:
314+
# This name MUST be "pgbouncer"
315+
- name: pgbouncer
316+
resources:
317+
requests:
318+
cpu: "0.1"
319+
memory: 100Mi
320+
limits:
321+
cpu: "0.5"
322+
memory: 500Mi
323+
```
324+
325+
## PgBouncer image
326+
327+
By default, {{name.ln}} deploys the
328+
[latest stable PgBouncer image](https://docker.enterprisedb.com/k8s/pgbouncer)
329+
the operator was built against. You can override that default in three ways.
330+
When more than one is set, the sources are evaluated top-down — the first
331+
match in the list below is used; if none match, the operator's built-in
332+
default applies:
333+
334+
1. An explicit image set on the `pgbouncer` container inside
335+
`spec.template.spec.containers` (escape hatch — see
336+
[Pod-template override](#pod-template-override) below).
337+
2. `spec.pgbouncer.image` — an image reference set directly on the `Pooler`.
338+
3. `spec.pgbouncer.imageCatalogRef` — a reference to an entry in an
339+
`ImageCatalog` or `ClusterImageCatalog`.
340+
341+
`spec.pgbouncer.image` and `spec.pgbouncer.imageCatalogRef` are mutually
342+
exclusive — set at most one.
343+
344+
!!!warning Policy gating
345+
346+
If you enforce admission policies that restrict which PgBouncer images
347+
may run, those policies **must gate all three** image sources:
348+
`spec.pgbouncer.image`, `spec.pgbouncer.imageCatalogRef`, and the
349+
`image` field on a `pgbouncer` container inside
350+
`spec.template.spec.containers`. A policy that covers only the first
351+
two leaves the pod-template override as an unguarded escape hatch.
352+
The same consideration applies to `Cluster.spec.imageName` and
353+
`Cluster.spec.imageCatalogRef`.
354+
!!!
355+
356+
### Setting an explicit image
357+
358+
Use `spec.pgbouncer.image` to pin a specific PgBouncer version or pull from
359+
a private registry:
360+
361+
```yaml
362+
apiVersion: postgresql.k8s.enterprisedb.io/v1
363+
kind: Pooler
364+
metadata:
365+
name: pooler-example-rw
366+
spec:
367+
cluster:
368+
name: cluster-example
369+
instances: 3
370+
type: rw
371+
pgbouncer:
372+
poolMode: session
373+
image: docker.enterprisedb.com/k8s/pgbouncer:1.25.1-ubi9
374+
```
375+
376+
### Using an image catalog
284377

285-
You can specify a custom image and define resource requests/limits. Note that
286-
the container name is explicitly set to `pgbouncer`.
378+
The `Pooler` resource can manage the PgBouncer container image centrally via
379+
an `ImageCatalog` or `ClusterImageCatalog`, following the same pattern as
380+
`Cluster` resources (see [Image Catalog](image_catalog.md)). The catalog
381+
entry is selected by the `key` defined in the catalog's `componentImages`
382+
list.
383+
384+
Reference a catalog entry with `spec.pgbouncer.imageCatalogRef`:
287385

288386
```yaml
289387
apiVersion: postgresql.k8s.enterprisedb.io/v1
@@ -295,29 +393,68 @@ spec:
295393
name: cluster-example
296394
instances: 3
297395
type: rw
396+
pgbouncer:
397+
poolMode: session
398+
imageCatalogRef:
399+
apiGroup: postgresql.k8s.enterprisedb.io
400+
kind: ImageCatalog
401+
name: my-catalog
402+
key: pgbouncer
403+
```
404+
405+
To use a cluster-wide catalog instead, set `kind: ClusterImageCatalog` and
406+
point `name` at the corresponding resource — the rest of the spec is
407+
identical.
408+
409+
When a catalog entry is updated, the operator automatically reconciles all
410+
poolers referencing it and rolls out the new image without any change to the
411+
`Pooler` spec.
298412

413+
### Pod-template override
414+
415+
The pod template can also carry an `image` on the `pgbouncer` container, in
416+
which case it overrides every other source (including `spec.pgbouncer.image`
417+
and `spec.pgbouncer.imageCatalogRef`). Treat this as an **escape hatch** —
418+
use it only when you need to customize other container-level settings
419+
(resources, environment, security context) and happen to want to pin the
420+
image in the same place. For routine image changes, prefer
421+
`spec.pgbouncer.image` or an image catalog: those fields are validated,
422+
mutually exclusive, and visible to admission policies that gate the
423+
PgBouncer image (see [Pod templates](#pod-templates) for the broader
424+
template mechanics):
425+
426+
```yaml
427+
# ...
299428
template:
300-
metadata:
301-
labels:
302-
app: pooler
303429
spec:
304430
containers:
305-
# This name MUST be "pgbouncer"
306431
- name: pgbouncer
307432
image: my-pgbouncer:latest
308-
resources:
309-
requests:
310-
cpu: "0.1"
311-
memory: 100Mi
312-
limits:
313-
cpu: "0.5"
314-
memory: 500Mi
315433
```
316434

435+
### Monitoring the resolved image
436+
437+
The operator stores the resolved image in `status.image` and reflects the
438+
outcome in `status.phase`, one of `active`, `paused`, `inactive`, or
439+
`failed`. On `failed`, `status.phaseReason` describes the cause (for
440+
example, if the catalog or key does not exist). You can inspect the
441+
current state with:
442+
443+
```shell
444+
kubectl get pooler pooler-example-rw -o jsonpath='{.status.image}'
445+
```
446+
447+
!!!note API reference
448+
449+
For details, see [`PgBouncerSpec`](pg4k.v1.md#pgbouncerspec)
450+
in the API reference.
451+
!!!
452+
317453
## Service Template
318454

319-
Sometimes, your pooler will require some different labels, annotations, or even change
320-
the type of the service, you can achieve that by using the `serviceTemplate` field:
455+
Sometimes, your pooler will require some different labels, annotations, or
456+
even a different Service type. You can achieve that by using the
457+
`serviceTemplate` field:
321458

322459
```yaml
323460
apiVersion: postgresql.k8s.enterprisedb.io/v1
@@ -668,6 +805,42 @@ spec:
668805
- port: metrics
669806
```
670807

808+
### TLS for the Metrics Endpoint
809+
810+
Set `.spec.monitoring.tls.enabled: true` to serve the metrics endpoint over
811+
HTTPS. By default, the cluster's server certificate is being used.
812+
The certificate is reloaded on every TLS handshake, so rotations are
813+
picked up without restarting the pod.
814+
815+
```yaml
816+
spec:
817+
monitoring:
818+
tls:
819+
enabled: true
820+
```
821+
822+
When `.spec.pgbouncer.clientTLSSecret` is set, the metrics server presents
823+
that certificate instead.
824+
825+
```yaml
826+
spec:
827+
pgbouncer:
828+
clientTLSSecret:
829+
name: <CLIENT_TLS_SECRET>
830+
monitoring:
831+
tls:
832+
enabled: true
833+
```
834+
835+
The generated `PodMonitor` scrapes with `insecureSkipVerify=true` because
836+
Prometheus scrapes pods by IP and the certificate's SANs do not generally
837+
cover the pod IP.
838+
839+
If you need strict verification, set `.spec.monitoring.enablePodMonitor: false`
840+
and manage the `PodMonitor` yourself: the operator-generated one is hardcoded
841+
to `insecureSkipVerify=true` and overwrites its spec on every reconcile, so a
842+
manual patch on the generated `PodMonitor` would not survive.
843+
671844
### Deprecation of Automatic `PodMonitor` Creation
672845

673846
!!!warning Feature Deprecation Notice
@@ -704,7 +877,7 @@ following example:
704877
## Pausing connections
705878

706879
The `Pooler` specification allows you to take advantage of PgBouncer's `PAUSE`
707-
and `RESUME` commands, using only declarative configuration. You can ado this
880+
and `RESUME` commands, using only declarative configuration. You can do this
708881
using the `paused` option, which by default is set to `false`. When set to
709882
`true`, the operator internally invokes the `PAUSE` command in PgBouncer,
710883
which:

product_docs/docs/postgres_for_kubernetes/1/database_import.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ As a result, the instructions in this section are suitable for both:
2222
- importing one or more databases from an existing PostgreSQL instance, even
2323
outside Kubernetes
2424
- importing the database from any PostgreSQL version to one that is either the
25-
same or newer, enabling *major upgrades* of PostgreSQL (e.g. from version 13.x
26-
to version 17.x)
25+
same or newer, enabling *major upgrades* of PostgreSQL (e.g. from version 14.x
26+
to version 18.x)
2727

2828
!!!warning
2929
When performing major upgrades of PostgreSQL you are responsible for making

0 commit comments

Comments
 (0)