From 46f475652a13ace6d05949155bad005c9d777c7a Mon Sep 17 00:00:00 2001 From: mbu Date: Tue, 6 Jan 2026 11:22:38 +0100 Subject: [PATCH 1/4] feat: imagePullSecret functionality --- manifests/postgresql.crd.yaml | 10 ++++++++++ pkg/apis/acid.zalan.do/v1/postgresql_type.go | 13 +++++++------ pkg/cluster/connection_pooler.go | 4 ++++ 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/manifests/postgresql.crd.yaml b/manifests/postgresql.crd.yaml index 7a1b21a4d..161364bd0 100644 --- a/manifests/postgresql.crd.yaml +++ b/manifests/postgresql.crd.yaml @@ -136,6 +136,16 @@ spec: connectionPooler: type: object properties: + imagePullSecrets: + type: array + nullable: true + items: + type: object + required: + - name + properties: + name: + type: string dockerImage: type: string maxDBConnections: diff --git a/pkg/apis/acid.zalan.do/v1/postgresql_type.go b/pkg/apis/acid.zalan.do/v1/postgresql_type.go index ef6dfe7ff..6533f3b16 100644 --- a/pkg/apis/acid.zalan.do/v1/postgresql_type.go +++ b/pkg/apis/acid.zalan.do/v1/postgresql_type.go @@ -242,12 +242,13 @@ type PostgresStatus struct { // makes sense to expose. E.g. pool size (min/max boundaries), max client // connections etc. type ConnectionPooler struct { - NumberOfInstances *int32 `json:"numberOfInstances,omitempty"` - Schema string `json:"schema,omitempty"` - User string `json:"user,omitempty"` - Mode string `json:"mode,omitempty"` - DockerImage string `json:"dockerImage,omitempty"` - MaxDBConnections *int32 `json:"maxDBConnections,omitempty"` + NumberOfInstances *int32 `json:"numberOfInstances,omitempty"` + Schema string `json:"schema,omitempty"` + User string `json:"user,omitempty"` + Mode string `json:"mode,omitempty"` + DockerImage string `json:"dockerImage,omitempty"` + MaxDBConnections *int32 `json:"maxDBConnections,omitempty"` + ImagePullSecrets []v1.LocalObjectReference `json:"imagePullSecrets,omitempty"` *Resources `json:"resources,omitempty"` } diff --git a/pkg/cluster/connection_pooler.go b/pkg/cluster/connection_pooler.go index ac4ce67d8..63a281005 100644 --- a/pkg/cluster/connection_pooler.go +++ b/pkg/cluster/connection_pooler.go @@ -412,6 +412,10 @@ func (c *Cluster) generateConnectionPoolerPodTemplate(role PostgresRole) ( }, } + if len(connectionPoolerSpec.ImagePullSecrets) > 0 { + podTemplate.Spec.ImagePullSecrets = connectionPoolerSpec.ImagePullSecrets + } + nodeAffinity := c.nodeAffinity(c.OpConfig.NodeReadinessLabel, spec.NodeAffinity) if c.OpConfig.EnablePodAntiAffinity { labelsSet := labels.Set(c.connectionPoolerLabels(role, false).MatchLabels) From 0350ce9150b8ac108f8e8302de19ac7b9b977fbb Mon Sep 17 00:00:00 2001 From: mbuken Date: Tue, 6 Jan 2026 13:22:59 +0100 Subject: [PATCH 2/4] feat: documentation --- docs/reference/cluster_manifest.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/reference/cluster_manifest.md b/docs/reference/cluster_manifest.md index ab0353202..1243e28d3 100644 --- a/docs/reference/cluster_manifest.md +++ b/docs/reference/cluster_manifest.md @@ -588,6 +588,9 @@ for both master and replica pooler services (if `enableReplicaConnectionPooler` User to create for connection pooler to be able to connect to a database. You can also choose a role from the `users` section or a system user role. +* **imagePullSecrets** + References an existing Kubernetes secret to use when pulling a custom pooler image. + * **dockerImage** Which docker image to use for connection pooler deployment. From 3313a378d809085f444aa6d80623699cfdfd0caf Mon Sep 17 00:00:00 2001 From: mbuken Date: Mon, 12 Jan 2026 07:46:22 +0100 Subject: [PATCH 3/4] fix: imagePullSecrets in all necessary places --- charts/postgres-operator/crds/postgresqls.yaml | 10 ++++++++++ pkg/apis/acid.zalan.do/v1/crds.go | 13 +++++++++++++ 2 files changed, 23 insertions(+) diff --git a/charts/postgres-operator/crds/postgresqls.yaml b/charts/postgres-operator/crds/postgresqls.yaml index 667c58efa..ec9fb4afc 100644 --- a/charts/postgres-operator/crds/postgresqls.yaml +++ b/charts/postgres-operator/crds/postgresqls.yaml @@ -138,6 +138,16 @@ spec: connectionPooler: type: object properties: + imagePullSecrets: + type: array + nullable: true + items: + type: object + required: + - name + properties: + name: + type: string dockerImage: type: string maxDBConnections: diff --git a/pkg/apis/acid.zalan.do/v1/crds.go b/pkg/apis/acid.zalan.do/v1/crds.go index b89cb1448..8beb87c68 100644 --- a/pkg/apis/acid.zalan.do/v1/crds.go +++ b/pkg/apis/acid.zalan.do/v1/crds.go @@ -220,6 +220,19 @@ var PostgresCRDResourceValidation = apiextv1.CustomResourceValidation{ "connectionPooler": { Type: "object", Properties: map[string]apiextv1.JSONSchemaProps{ + "imagePullSecrets": { + Type: "array", + Nullable: true, + Items: &apiextv1.JSONSchemaPropsOrArray{ + Schema: &apiextv1.JSONSchemaProps{ + Type: "object", + Required: []string{"name"}, + Properties: map[string]apiextv1.JSONSchemaProps{ + "name": {Type: "string"}, + }, + }, + }, + }, "dockerImage": { Type: "string", }, From 763b502e5d9d434285e6b2b24e836339c4a63f57 Mon Sep 17 00:00:00 2001 From: mbuken Date: Thu, 12 Mar 2026 09:42:38 +0100 Subject: [PATCH 4/4] chore: update crds after make test --- manifests/postgresql.crd.yaml | 28 ++++++++++++------- pkg/apis/acid.zalan.do/v1/postgresql.crd.yaml | 18 ++++++++++++ .../acid.zalan.do/v1/zz_generated.deepcopy.go | 5 ++++ 3 files changed, 41 insertions(+), 10 deletions(-) diff --git a/manifests/postgresql.crd.yaml b/manifests/postgresql.crd.yaml index 04bb41900..dab035c54 100644 --- a/manifests/postgresql.crd.yaml +++ b/manifests/postgresql.crd.yaml @@ -152,18 +152,26 @@ spec: makes sense to expose. E.g. pool size (min/max boundaries), max client connections etc. properties: - imagePullSecrets: - type: array - nullable: true - items: - type: object - required: - - name - properties: - name: - type: string dockerImage: type: string + imagePullSecrets: + items: + description: |- + LocalObjectReference contains enough information to let you locate the + referenced object inside the same namespace. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + type: array maxDBConnections: format: int32 type: integer diff --git a/pkg/apis/acid.zalan.do/v1/postgresql.crd.yaml b/pkg/apis/acid.zalan.do/v1/postgresql.crd.yaml index 39811824e..dab035c54 100644 --- a/pkg/apis/acid.zalan.do/v1/postgresql.crd.yaml +++ b/pkg/apis/acid.zalan.do/v1/postgresql.crd.yaml @@ -154,6 +154,24 @@ spec: properties: dockerImage: type: string + imagePullSecrets: + items: + description: |- + LocalObjectReference contains enough information to let you locate the + referenced object inside the same namespace. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + type: array maxDBConnections: format: int32 type: integer diff --git a/pkg/apis/acid.zalan.do/v1/zz_generated.deepcopy.go b/pkg/apis/acid.zalan.do/v1/zz_generated.deepcopy.go index 159a87f35..634afbf51 100644 --- a/pkg/apis/acid.zalan.do/v1/zz_generated.deepcopy.go +++ b/pkg/apis/acid.zalan.do/v1/zz_generated.deepcopy.go @@ -111,6 +111,11 @@ func (in *ConnectionPooler) DeepCopyInto(out *ConnectionPooler) { *out = new(int32) **out = **in } + if in.ImagePullSecrets != nil { + in, out := &in.ImagePullSecrets, &out.ImagePullSecrets + *out = make([]corev1.LocalObjectReference, len(*in)) + copy(*out, *in) + } if in.Resources != nil { in, out := &in.Resources, &out.Resources *out = new(Resources)