pkg/resources/statefulset/pod_affinities.go (29 lines of code) (raw):
// Copyright (c) 2022, Oracle and/or its affiliates.
//
// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
package statefulset
import (
"github.com/mysql/ndb-operator/pkg/constants"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// GetPodAntiAffinityRules returns the PodAntiAffinity definition
// with the given mySQLClusterNodeTypes. The mySQLClusterNodeTypes
// should be in the order of most to least preferred node type for
// co-location. The defined PodAntiAffinity rules ensure that the
// scheduler will first attempt to schedule the new pod onto a K8s
// worker node where none of the given mySQLClusterNodeTypes are
// running. If no such worker node is available, then the new pod
// will be co-located with existing MySQL Cluster node pods based
// on the preference specified via mySQLClusterNodeTypes.
func GetPodAntiAffinityRules(mySQLClusterNodeTypes []constants.NdbNodeType) *corev1.PodAntiAffinity {
if len(mySQLClusterNodeTypes) != 3 {
panic("GetPodAntiAffinityRules can handle only 3 MySQL Cluster NodeTypes")
}
// Use weights based on node type preference. Lower weights for
// node types with higher preference and vice versa as the
// Anti-Affinity is being defined here.
//
// K8s calculates the weight of a worker node based on Anti
// Affinities by adding -1 * Weight of the PodAffinityTerm for
// every pod that matches the PodAffinityTerm and runs in that
// worker node. The new Pod will be scheduled on the worker node
// with the most weight.
//
// Example :
// Given 3 NodeTypes A, B, C, where A is the most preferred and
// C is the least, the weights 5, 25, 50 ensure that the worker
// nodes have the following order of preference when a new pod
// with the AntiAffinity rule defined by this function has to
// be scheduled onto one of them :
// Worker Node where
// (total weight of that worker node in bracket)
// 1. No MySQL Cluster Nodes running (0)
// 2. Only NodeType A is running (-5)
// 3. Only NodeType B is running (-25)
// 4. NodeTypes A and B are running (-30)
// 5. Only NodeType C is running (-50)
// 6. NodeTypes A and C are running (-55)
// 7. NodeTypes B and C are running (-75)
// 8. All NodeTypes A, B, C are running (-80)
weights := []int32{5, 25, 50}
// Generate the WeightedPodAffinities to be set in the PodAntiAffinity
var weightedPodAffinities []corev1.WeightedPodAffinityTerm
for i, mysqlClusterNodeType := range mySQLClusterNodeTypes {
weightedPodAffinities = append(weightedPodAffinities, corev1.WeightedPodAffinityTerm{
Weight: weights[i],
PodAffinityTerm: corev1.PodAffinityTerm{
LabelSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
constants.ClusterNodeTypeLabel: mysqlClusterNodeType,
},
},
TopologyKey: "kubernetes.io/hostname",
},
})
}
return &corev1.PodAntiAffinity{
PreferredDuringSchedulingIgnoredDuringExecution: weightedPodAffinities,
}
}