Skip to content

Commit 26a7fdf

Browse files
bot-TeutoNetsdudoladov
authored andcommitted
Add Pod Anti Affinity (zalando#489)
* Add Pod Anti Affinity
1 parent 2e9b653 commit 26a7fdf

File tree

6 files changed

+73
-2
lines changed

6 files changed

+73
-2
lines changed

docs/administrator.md

+30
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,36 @@ Postgres pods by default receive tolerations for `unreachable` and `noExecute` t
151151
Depending on your setup, you may want to adjust these parameters to prevent master pods from being evicted by the Kubernetes runtime.
152152
To prevent eviction completely, specify the toleration by leaving out the `tolerationSeconds` value (similar to how Kubernetes' own DaemonSets are configured)
153153

154+
### Enable pod anti affinity
155+
156+
To ensure Postgres pods are running on different topologies, you can use [pod anti affinity](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/)
157+
and configure the required topology in the operator ConfigMap.
158+
159+
Enable pod anti affinity by adding following line to the operator ConfigMap:
160+
161+
```yaml
162+
apiVersion: v1
163+
kind: ConfigMap
164+
metadata:
165+
name: postgres-operator
166+
data:
167+
enable_pod_antiaffinity: "true"
168+
```
169+
170+
By default the topology key for the pod anti affinity is set to `kubernetes.io/hostname`,
171+
you can set another topology key e.g. `failure-domain.beta.kubernetes.io/zone` by adding following line
172+
to the operator ConfigMap, see [built-in node labels](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#interlude-built-in-node-labels) for available topology keys:
173+
174+
```yaml
175+
apiVersion: v1
176+
kind: ConfigMap
177+
metadata:
178+
name: postgres-operator
179+
data:
180+
enable_pod_antiaffinity: "true"
181+
pod_antiaffinity_topology_key: "failure-domain.beta.kubernetes.io/zone"
182+
```
183+
154184
### Add cluster-specific labels
155185

156186
In some cases, you might want to add `labels` that are specific to a given

docs/reference/operator_parameters.md

+8
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,14 @@ configuration they are grouped under the `kubernetes` key.
213213
that should be assigned to the Postgres pods. The priority class itself must be defined in advance.
214214
Default is empty (use the default priority class).
215215

216+
* **enable_pod_antiaffinity**
217+
toggles [pod anti affinity](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/) on the Postgres pods, to avoid multiple pods
218+
of the same Postgres cluster in the same topology , e.g. node. The default is `false`.
219+
220+
* **pod_antiaffinity_topology_key**
221+
override
222+
[topology key](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#interlude-built-in-node-labels)
223+
for pod anti affinity. The default is `kubernetes.io/hostname`.
216224

217225
## Kubernetes resource requests
218226

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

+2
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ type KubernetesMetaConfiguration struct {
6060
// TODO: use namespacedname
6161
PodEnvironmentConfigMap string `json:"pod_environment_configmap,omitempty"`
6262
PodPriorityClassName string `json:"pod_priority_class_name,omitempty"`
63+
EnablePodAntiAffinity bool `json:"enable_pod_antiaffinity" default:"false"`
64+
PodAntiAffinityTopologyKey string `name:"pod_antiaffinity_topology_key" default:"kubernetes.io/hostname"`
6365
}
6466

6567
// PostgresPodResourcesDefaults defines the spec of default resources

pkg/cluster/k8sres.go

+28-2
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,26 @@ func nodeAffinity(nodeReadinessLabel map[string]string) *v1.Affinity {
290290
}
291291
}
292292

293+
func generatePodAffinity(labels labels.Set, topologyKey string, nodeAffinity *v1.Affinity) *v1.Affinity {
294+
// generate pod anti-affinity to avoid multiple pods of the same Postgres cluster in the same topology , e.g. node
295+
podAffinity := v1.Affinity{
296+
PodAntiAffinity: &v1.PodAntiAffinity{
297+
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{{
298+
LabelSelector: &metav1.LabelSelector{
299+
MatchLabels: labels,
300+
},
301+
TopologyKey: topologyKey,
302+
}},
303+
},
304+
}
305+
306+
if nodeAffinity != nil && nodeAffinity.NodeAffinity != nil {
307+
podAffinity.NodeAffinity = nodeAffinity.NodeAffinity
308+
}
309+
310+
return &podAffinity
311+
}
312+
293313
func tolerations(tolerationsSpec *[]v1.Toleration, podToleration map[string]string) []v1.Toleration {
294314
// allow to override tolerations by postgresql manifest
295315
if len(*tolerationsSpec) > 0 {
@@ -419,6 +439,8 @@ func generatePodTemplate(
419439
kubeIAMRole string,
420440
priorityClassName string,
421441
shmVolume bool,
442+
podAntiAffinity bool,
443+
podAntiAffinityTopologyKey string,
422444
) (*v1.PodTemplateSpec, error) {
423445

424446
terminateGracePeriodSeconds := terminateGracePeriod
@@ -437,7 +459,9 @@ func generatePodTemplate(
437459
addShmVolume(&podSpec)
438460
}
439461

440-
if nodeAffinity != nil {
462+
if podAntiAffinity {
463+
podSpec.Affinity = generatePodAffinity(labels, podAntiAffinityTopologyKey, nodeAffinity)
464+
} else if nodeAffinity != nil {
441465
podSpec.Affinity = nodeAffinity
442466
}
443467

@@ -813,7 +837,9 @@ func (c *Cluster) generateStatefulSet(spec *acidv1.PostgresSpec) (*v1beta1.State
813837
c.OpConfig.PodServiceAccountName,
814838
c.OpConfig.KubeIAMRole,
815839
effectivePodPriorityClassName,
816-
mountShmVolumeNeeded(c.OpConfig, spec)); err != nil {
840+
mountShmVolumeNeeded(c.OpConfig, spec),
841+
c.OpConfig.EnablePodAntiAffinity,
842+
c.OpConfig.PodAntiAffinityTopologyKey); err != nil {
817843
return nil, fmt.Errorf("could not generate pod template: %v", err)
818844
}
819845

pkg/controller/operator_config.go

+3
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur
5353
result.NodeReadinessLabel = fromCRD.Kubernetes.NodeReadinessLabel
5454
result.PodPriorityClassName = fromCRD.Kubernetes.PodPriorityClassName
5555

56+
result.EnablePodAntiAffinity = fromCRD.Kubernetes.EnablePodAntiAffinity;
57+
result.PodAntiAffinityTopologyKey = fromCRD.Kubernetes.PodAntiAffinityTopologyKey;
58+
5659
result.DefaultCPURequest = fromCRD.PostgresPodResources.DefaultCPURequest
5760
result.DefaultMemoryRequest = fromCRD.PostgresPodResources.DefaultMemoryRequest
5861
result.DefaultCPULimit = fromCRD.PostgresPodResources.DefaultCPULimit

pkg/util/config/config.go

+2
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ type Config struct {
9595
EnableMasterLoadBalancer bool `name:"enable_master_load_balancer" default:"true"`
9696
EnableReplicaLoadBalancer bool `name:"enable_replica_load_balancer" default:"false"`
9797
CustomServiceAnnotations map[string]string `name:"custom_service_annotations"`
98+
EnablePodAntiAffinity bool `name:"enable_pod_antiaffinity" default:"false"`
99+
PodAntiAffinityTopologyKey string `name:"pod_antiaffinity_topology_key" default:"kubernetes.io/hostname"`
98100
// deprecated and kept for backward compatibility
99101
EnableLoadBalancer *bool `name:"enable_load_balancer"`
100102
MasterDNSNameFormat StringTemplate `name:"master_dns_name_format" default:"{cluster}.{team}.{hostedzone}"`

0 commit comments

Comments
 (0)