Skip to content

Commit 1ddf175

Browse files
Add topologySpreadConstraints configuration to pod spec.
1 parent 37d6993 commit 1ddf175

File tree

8 files changed

+97
-2
lines changed

8 files changed

+97
-2
lines changed

manifests/postgresql.crd.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,12 @@ spec:
575575
- PreferNoSchedule
576576
tolerationSeconds:
577577
type: integer
578+
topologySpreadConstraints:
579+
type: array
580+
nullable: true
581+
items:
582+
type: object
583+
x-kubernetes-preserve-unknown-fields: true
578584
useLoadBalancer:
579585
type: boolean
580586
description: deprecated

pkg/apis/acid.zalan.do/v1/crds.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -898,6 +898,16 @@ var PostgresCRDResourceValidation = apiextv1.CustomResourceValidation{
898898
},
899899
},
900900
},
901+
"topologySpreadConstraints": {
902+
Type: "array",
903+
Nullable: true,
904+
Items: &apiextv1.JSONSchemaPropsOrArray{
905+
Schema: &apiextv1.JSONSchemaProps{
906+
Type: "object",
907+
XPreserveUnknownFields: util.True(),
908+
},
909+
},
910+
},
901911
"useLoadBalancer": {
902912
Type: "boolean",
903913
Description: "deprecated",

pkg/apis/acid.zalan.do/v1/operator_configuration_type.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ type KubernetesMetaConfiguration struct {
107107
EnableReadinessProbe bool `json:"enable_readiness_probe,omitempty"`
108108
EnableCrossNamespaceSecret bool `json:"enable_cross_namespace_secret,omitempty"`
109109
EnableFinalizers *bool `json:"enable_finalizers,omitempty"`
110+
EnablePostgresTopologySpreadConstraints bool `json:"enable_postgres_topology_spread_constraints,omitempty"`
110111
}
111112

112113
// PostgresPodResourcesDefaults defines the spec of default resources

pkg/apis/acid.zalan.do/v1/postgresql_type.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ type PostgresSpec struct {
9393
// deprecated json tags
9494
InitContainersOld []v1.Container `json:"init_containers,omitempty"`
9595
PodPriorityClassNameOld string `json:"pod_priority_class_name,omitempty"`
96+
97+
AdditionalTopologySpreadConstraints []v1.TopologySpreadConstraint `json:"additionalTopologySpreadConstraints,omitempty"`
9698
}
9799

98100
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

pkg/cluster/cluster.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,11 @@ func (c *Cluster) compareStatefulSetWith(statefulSet *appsv1.StatefulSet) *compa
472472
needsRollUpdate = true
473473
reasons = append(reasons, "new statefulset's pod affinity does not match the current one")
474474
}
475+
if !reflect.DeepEqual(c.Statefulset.Spec.Template.Spec.TopologySpreadConstraints, statefulSet.Spec.Template.Spec.TopologySpreadConstraints) {
476+
needsReplace = true
477+
needsRollUpdate = true
478+
reasons = append(reasons, "new statefulset's pod topologySpreadConstraints does not match the current one")
479+
}
475480
if len(c.Statefulset.Spec.Template.Spec.Tolerations) != len(statefulSet.Spec.Template.Spec.Tolerations) {
476481
needsReplace = true
477482
needsRollUpdate = true

pkg/cluster/k8sres.go

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,22 @@ func generatePodAntiAffinity(podAffinityTerm v1.PodAffinityTerm, preferredDuring
610610
return podAntiAffinity
611611
}
612612

613+
func generateTopologySpreadConstraints(labels labels.Set, additionalTopologySpreadConstraints []v1.TopologySpreadConstraint) []v1.TopologySpreadConstraint {
614+
topologySpreadConstraint := v1.TopologySpreadConstraint{
615+
MaxSkew: int32(1),
616+
TopologyKey: "topology.kubernetes.io/zone",
617+
WhenUnsatisfiable: v1.DoNotSchedule,
618+
LabelSelector: &metav1.LabelSelector{
619+
MatchLabels: labels,
620+
},
621+
}
622+
topologySpreadConstraints := []v1.TopologySpreadConstraint{topologySpreadConstraint}
623+
if len(additionalTopologySpreadConstraints) > 0 {
624+
topologySpreadConstraints = append(topologySpreadConstraints, additionalTopologySpreadConstraints...)
625+
}
626+
return topologySpreadConstraints
627+
}
628+
613629
func tolerations(tolerationsSpec *[]v1.Toleration, podToleration map[string]string) []v1.Toleration {
614630
// allow to override tolerations by postgresql manifest
615631
if len(*tolerationsSpec) > 0 {
@@ -832,6 +848,8 @@ func (c *Cluster) generatePodTemplate(
832848
additionalSecretMount string,
833849
additionalSecretMountPath string,
834850
additionalVolumes []acidv1.AdditionalVolume,
851+
topologySpreadConstraints bool,
852+
additionalTopologySpreadConstraints []v1.TopologySpreadConstraint,
835853
) (*v1.PodTemplateSpec, error) {
836854

837855
terminateGracePeriodSeconds := terminateGracePeriod
@@ -884,6 +902,10 @@ func (c *Cluster) generatePodTemplate(
884902
podSpec.PriorityClassName = priorityClassName
885903
}
886904

905+
if topologySpreadConstraints {
906+
podSpec.TopologySpreadConstraints = generateTopologySpreadConstraints(labels, additionalTopologySpreadConstraints)
907+
}
908+
887909
if sharePgSocketWithSidecars != nil && *sharePgSocketWithSidecars {
888910
addVarRunVolume(&podSpec)
889911
}
@@ -1487,7 +1509,9 @@ func (c *Cluster) generateStatefulSet(spec *acidv1.PostgresSpec) (*appsv1.Statef
14871509
c.OpConfig.PodAntiAffinityPreferredDuringScheduling,
14881510
c.OpConfig.AdditionalSecretMount,
14891511
c.OpConfig.AdditionalSecretMountPath,
1490-
additionalVolumes)
1512+
additionalVolumes,
1513+
c.OpConfig.EnablePostgresTopologySpreadConstraints,
1514+
spec.AdditionalTopologySpreadConstraints)
14911515

14921516
if err != nil {
14931517
return nil, fmt.Errorf("could not generate pod template: %v", err)
@@ -2334,7 +2358,9 @@ func (c *Cluster) generateLogicalBackupJob() (*batchv1.CronJob, error) {
23342358
false,
23352359
c.OpConfig.AdditionalSecretMount,
23362360
c.OpConfig.AdditionalSecretMountPath,
2337-
[]acidv1.AdditionalVolume{}); err != nil {
2361+
[]acidv1.AdditionalVolume{},
2362+
true,
2363+
[]v1.TopologySpreadConstraint{}); err != nil {
23382364
return nil, fmt.Errorf("could not generate pod template for logical backup pod: %v", err)
23392365
}
23402366

pkg/cluster/k8sres_test.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3795,3 +3795,47 @@ func TestGenerateCapabilities(t *testing.T) {
37953795
}
37963796
}
37973797
}
3798+
3799+
func TestTopologySpreadConstraints(t *testing.T) {
3800+
clusterName := "acid-test-cluster"
3801+
namespace := "default"
3802+
3803+
pg := acidv1.Postgresql{
3804+
ObjectMeta: metav1.ObjectMeta{
3805+
Name: clusterName,
3806+
Namespace: namespace,
3807+
},
3808+
Spec: acidv1.PostgresSpec{
3809+
NumberOfInstances: 1,
3810+
Resources: &acidv1.Resources{
3811+
ResourceRequests: acidv1.ResourceDescription{CPU: k8sutil.StringToPointer("1"), Memory: k8sutil.StringToPointer("10")},
3812+
ResourceLimits: acidv1.ResourceDescription{CPU: k8sutil.StringToPointer("1"), Memory: k8sutil.StringToPointer("10")},
3813+
},
3814+
Volume: acidv1.Volume{
3815+
Size: "1G",
3816+
},
3817+
},
3818+
}
3819+
3820+
cluster := New(
3821+
Config{
3822+
OpConfig: config.Config{
3823+
PodManagementPolicy: "ordered_ready",
3824+
EnablePostgresTopologySpreadConstraints: true,
3825+
},
3826+
}, k8sutil.KubernetesClient{}, acidv1.Postgresql{}, logger, eventRecorder)
3827+
cluster.Name = clusterName
3828+
cluster.Namespace = namespace
3829+
cluster.labelsSet(true)
3830+
3831+
s, err := cluster.generateStatefulSet(&pg.Spec)
3832+
assert.NoError(t, err)
3833+
assert.Contains(t, s.Spec.Template.Spec.TopologySpreadConstraints, v1.TopologySpreadConstraint{
3834+
MaxSkew: int32(1),
3835+
TopologyKey: "topology.kubernetes.io/zone",
3836+
WhenUnsatisfiable: v1.DoNotSchedule,
3837+
LabelSelector: &metav1.LabelSelector{
3838+
MatchLabels: cluster.labelsSet(true),
3839+
},
3840+
})
3841+
}

pkg/util/config/config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ type Config struct {
253253
EnableSecretsDeletion *bool `name:"enable_secrets_deletion" default:"true"`
254254
EnablePersistentVolumeClaimDeletion *bool `name:"enable_persistent_volume_claim_deletion" default:"true"`
255255
PersistentVolumeClaimRetentionPolicy map[string]string `name:"persistent_volume_claim_retention_policy" default:"when_deleted:retain,when_scaled:retain"`
256+
EnablePostgresTopologySpreadConstraints bool `json:"enable_postgres_topology_spread_constraints,omitempty"`
256257
}
257258

258259
// MustMarshal marshals the config or panics

0 commit comments

Comments
 (0)