From 54b01d21135d84294c4d2be1543b7110243b2fa9 Mon Sep 17 00:00:00 2001 From: matthias Date: Tue, 16 Dec 2025 18:15:10 +0100 Subject: [PATCH] add readinessprobe to exporter and optimize generateExporterSidecar --- .../v1/postgresql_type.go | 1 + .../v1/zz_generated.deepcopy.go | 5 ++ pkg/cluster/k8sres.go | 22 ++++++- pkg/cluster/resources.go | 58 +++++++++++++------ pkg/cluster/sync.go | 28 +++------ 5 files changed, 74 insertions(+), 40 deletions(-) diff --git a/pkg/apis/cpo.opensource.cybertec.at/v1/postgresql_type.go b/pkg/apis/cpo.opensource.cybertec.at/v1/postgresql_type.go index 3662ed57..51387778 100644 --- a/pkg/apis/cpo.opensource.cybertec.at/v1/postgresql_type.go +++ b/pkg/apis/cpo.opensource.cybertec.at/v1/postgresql_type.go @@ -221,6 +221,7 @@ type Sidecar struct { DockerImage string `json:"image,omitempty"` Ports []v1.ContainerPort `json:"ports,omitempty"` Env []v1.EnvVar `json:"env,omitempty"` + ReadinessProbe *v1.Probe `json:"readinessProbe,omitempty"` SecurityContext *v1.SecurityContext `json:"securityContext,omitempty"` VolumeMounts []v1.VolumeMount `json:"volumeMounts,omitempty"` } diff --git a/pkg/apis/cpo.opensource.cybertec.at/v1/zz_generated.deepcopy.go b/pkg/apis/cpo.opensource.cybertec.at/v1/zz_generated.deepcopy.go index 61b6327b..c29fe872 100644 --- a/pkg/apis/cpo.opensource.cybertec.at/v1/zz_generated.deepcopy.go +++ b/pkg/apis/cpo.opensource.cybertec.at/v1/zz_generated.deepcopy.go @@ -1507,6 +1507,11 @@ func (in *Sidecar) DeepCopyInto(out *Sidecar) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.ReadinessProbe != nil { + in, out := &in.ReadinessProbe, &out.ReadinessProbe + *out = new(corev1.Probe) + (*in).DeepCopyInto(*out) + } if in.SecurityContext != nil { in, out := &in.SecurityContext, &out.SecurityContext *out = new(corev1.SecurityContext) diff --git a/pkg/cluster/k8sres.go b/pkg/cluster/k8sres.go index 4e92c1ca..2234cd6a 100644 --- a/pkg/cluster/k8sres.go +++ b/pkg/cluster/k8sres.go @@ -1283,6 +1283,7 @@ func getSidecarContainer(sidecar cpov1.Sidecar, index int, resources *v1.Resourc Resources: *resources, Env: sidecar.Env, Ports: sidecar.Ports, + ReadinessProbe: sidecar.ReadinessProbe, SecurityContext: sidecar.SecurityContext, VolumeMounts: sidecar.VolumeMounts, } @@ -1317,7 +1318,7 @@ func extractPgVersionFromBinPath(binPath string, template string) (string, error return fmt.Sprintf("%v", pgVersion), nil } -func generateSpiloReadinessProbe() *v1.Probe { +func generatePatroniReadinessProbe() *v1.Probe { return &v1.Probe{ FailureThreshold: 3, ProbeHandler: v1.ProbeHandler{ @@ -1334,6 +1335,23 @@ func generateSpiloReadinessProbe() *v1.Probe { } } +func generateExporterReadinessProbe() *v1.Probe { + return &v1.Probe{ + FailureThreshold: 3, + ProbeHandler: v1.ProbeHandler{ + HTTPGet: &v1.HTTPGetAction{ + Path: "/", + Port: intstr.IntOrString{IntVal: 9187}, + Scheme: v1.URISchemeHTTP, + }, + }, + InitialDelaySeconds: 6, + PeriodSeconds: 10, + SuccessThreshold: 1, + TimeoutSeconds: 5, + } +} + func generatePatroniLivenessProbe() *v1.Probe { return &v1.Probe{ FailureThreshold: 6, @@ -1521,7 +1539,7 @@ func (c *Cluster) generateStatefulSet(spec *cpov1.PostgresSpec) (*appsv1.Statefu // Patroni responds 200 to probe only if it either owns the leader lock or postgres is running and DCS is accessible if c.OpConfig.EnableReadinessProbe { - spiloContainer.ReadinessProbe = generateSpiloReadinessProbe() + spiloContainer.ReadinessProbe = generatePatroniReadinessProbe() } // if c.OpConfig.EnableLivenessProbe { diff --git a/pkg/cluster/resources.go b/pkg/cluster/resources.go index e242dd74..b5122ccb 100644 --- a/pkg/cluster/resources.go +++ b/pkg/cluster/resources.go @@ -68,6 +68,42 @@ func (c *Cluster) listResources() error { return nil } +func hasSidecar(sidecars []cpov1.Sidecar, name string) bool { + for _, s := range sidecars { + if s.Name == name { + return true + } + } + return false +} + +func (c *Cluster) generateExporterSidecar() *cpov1.Sidecar { + monitor := c.Spec.Monitoring + sidecar := &cpov1.Sidecar{ + Name: "postgres-exporter", + DockerImage: monitor.Image, + Ports: []v1.ContainerPort{ + { + ContainerPort: monitorPort, + Protocol: v1.ProtocolTCP, + }, + }, + Env: c.generateMonitoringEnvVars(), + SecurityContext: &v1.SecurityContext{ + AllowPrivilegeEscalation: c.OpConfig.Resources.SpiloAllowPrivilegeEscalation, + Privileged: &c.OpConfig.Resources.SpiloPrivileged, + ReadOnlyRootFilesystem: util.True(), + Capabilities: generateCapabilities(c.OpConfig.AdditionalPodCapabilities), + }, + } + + if c.OpConfig.EnableReadinessProbe { + sidecar.ReadinessProbe = generateExporterReadinessProbe() + } + + return sidecar +} + func (c *Cluster) createStatefulSet() (*appsv1.StatefulSet, error) { c.setProcessName("creating statefulset") // check if it's allowed that spec contains initContainers @@ -82,25 +118,11 @@ func (c *Cluster) createStatefulSet() (*appsv1.StatefulSet, error) { } if c.Spec.Monitoring != nil { - monitor := c.Spec.Monitoring - sidecar := &cpov1.Sidecar{ - Name: "postgres-exporter", - DockerImage: monitor.Image, - Ports: []v1.ContainerPort{ - { - ContainerPort: monitorPort, - Protocol: v1.ProtocolTCP, - }, - }, - Env: c.generateMonitoringEnvVars(), - SecurityContext: &v1.SecurityContext{ - AllowPrivilegeEscalation: c.OpConfig.Resources.SpiloAllowPrivilegeEscalation, - Privileged: &c.OpConfig.Resources.SpiloPrivileged, - ReadOnlyRootFilesystem: util.True(), - Capabilities: generateCapabilities(c.OpConfig.AdditionalPodCapabilities), - }, + if exporterSidecar := c.generateExporterSidecar(); exporterSidecar != nil { + if !hasSidecar(c.Spec.Sidecars, "postgres-exporter") { + c.Spec.Sidecars = append(c.Spec.Sidecars, *exporterSidecar) + } } - c.Spec.Sidecars = append(c.Spec.Sidecars, *sidecar) //populate the sidecar spec so that the sidecar is automatically created } statefulSetSpec, err := c.generateStatefulSet(&c.Spec) diff --git a/pkg/cluster/sync.go b/pkg/cluster/sync.go index b0535481..1348e0b9 100644 --- a/pkg/cluster/sync.go +++ b/pkg/cluster/sync.go @@ -502,27 +502,15 @@ func (c *Cluster) syncStatefulSet() error { if err != nil { c.logger.Warnf("could not list pods of the statefulset: %v", err) } - if c.Spec.Monitoring != nil { // XXX: Why are we generating a sidecar in the sync code? - monitor := c.Spec.Monitoring - sidecar := &cpov1.Sidecar{ - Name: "postgres-exporter", - DockerImage: monitor.Image, - Ports: []v1.ContainerPort{ - { - ContainerPort: monitorPort, - Protocol: v1.ProtocolTCP, - }, - }, - Env: c.generateMonitoringEnvVars(), - SecurityContext: &v1.SecurityContext{ - AllowPrivilegeEscalation: c.OpConfig.Resources.SpiloAllowPrivilegeEscalation, - Privileged: &c.OpConfig.Resources.SpiloPrivileged, - ReadOnlyRootFilesystem: util.True(), - Capabilities: generateCapabilities(c.OpConfig.AdditionalPodCapabilities), - }, - } - c.Spec.Sidecars = append(c.Spec.Sidecars, *sidecar) //populate the sidecar spec so that the sidecar is automatically created + + if c.Spec.Monitoring != nil { + if exporterSidecar := c.generateExporterSidecar(); exporterSidecar != nil { + if !hasSidecar(c.Spec.Sidecars, "postgres-exporter") { + c.Spec.Sidecars = append(c.Spec.Sidecars, *exporterSidecar) + } + } } + // NB: Be careful to consider the codepath that acts on podsRollingUpdateRequired before returning early. sset, err := c.KubeClient.StatefulSets(c.Namespace).Get(context.TODO(), c.statefulSetName(), metav1.GetOptions{}) if err != nil {