-
Notifications
You must be signed in to change notification settings - Fork 669
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
pod anti-affinity check among nodes #1033
Changes from 5 commits
877d858
111055a
b55a886
5c07e13
f964b41
4d4baf9
db00e96
d32c20f
d55ad53
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -78,24 +78,36 @@ func (d *RemovePodsViolatingInterPodAntiAffinity) Name() string { | |
} | ||
|
||
func (d *RemovePodsViolatingInterPodAntiAffinity) Deschedule(ctx context.Context, nodes []*v1.Node) *framework.Status { | ||
podsList, err := d.handle.ClientSet().CoreV1().Pods("").List(ctx, metav1.ListOptions{}) | ||
if err != nil { | ||
return &framework.Status{ | ||
Err: fmt.Errorf("error listing all pods: %v", err), | ||
} | ||
} | ||
|
||
podsInANamespace := groupByNamespace(podsList) | ||
|
||
runningPodFilter := func(pod *v1.Pod) bool { | ||
return pod.Status.Phase != v1.PodSucceeded && pod.Status.Phase != v1.PodFailed | ||
} | ||
podsOnANode := groupByNodeName(podsList, podutil.WrapFilterFuncs(runningPodFilter, d.podFilter)) | ||
|
||
nodeMap := createNodeMap(nodes) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. could There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. or, maybe not nodeMap sorry... but looking at how we call There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you for your review and sorry for my late reply. I removed |
||
|
||
loop: | ||
for _, node := range nodes { | ||
klog.V(1).InfoS("Processing node", "node", klog.KObj(node)) | ||
pods, err := podutil.ListPodsOnANode(node.Name, d.handle.GetPodsAssignedToNodeFunc(), d.podFilter) | ||
if err != nil { | ||
return &framework.Status{ | ||
Err: fmt.Errorf("error listing pods: %v", err), | ||
} | ||
} | ||
// sort the evictable Pods based on priority, if there are multiple pods with same priority, they are sorted based on QoS tiers. | ||
pods := podsOnANode[node.Name] | ||
// sort the evict-able Pods based on priority, if there are multiple pods with same priority, they are sorted based on QoS tiers. | ||
podutil.SortPodsBasedOnPriorityLowToHigh(pods) | ||
totalPods := len(pods) | ||
for i := 0; i < totalPods; i++ { | ||
if checkPodsWithAntiAffinityExist(pods[i], pods) && d.handle.Evictor().Filter(pods[i]) && d.handle.Evictor().PreEvictionFilter(pods[i]) { | ||
if checkPodsWithAntiAffinityExist(pods[i], podsInANamespace, nodeMap) && d.handle.Evictor().Filter(pods[i]) && d.handle.Evictor().PreEvictionFilter(pods[i]) { | ||
if d.handle.Evictor().Evict(ctx, pods[i], evictions.EvictOptions{}) { | ||
// Since the current pod is evicted all other pods which have anti-affinity with this | ||
// pod need not be evicted. | ||
// Update pods. | ||
// Update allPods. | ||
podsInANamespace = removePodFromNamespaceMap(pods[i], podsInANamespace) | ||
pods = append(pods[:i], pods[i+1:]...) | ||
i-- | ||
totalPods-- | ||
|
@@ -109,8 +121,54 @@ loop: | |
return nil | ||
} | ||
|
||
func removePodFromNamespaceMap(podToRemove *v1.Pod, podMap map[string][]*v1.Pod) map[string][]*v1.Pod { | ||
podList, ok := podMap[podToRemove.Namespace] | ||
if !ok { | ||
return podMap | ||
} | ||
for i := 0; i < len(podList); i++ { | ||
podToCheck := podList[i] | ||
if podToRemove.Name == podToCheck.Name { | ||
podMap[podToRemove.Namespace] = append(podList[:i], podList[i+1:]...) | ||
return podMap | ||
} | ||
} | ||
return podMap | ||
} | ||
|
||
func groupByNamespace(pods *v1.PodList) map[string][]*v1.Pod { | ||
m := make(map[string][]*v1.Pod) | ||
for i := 0; i < len(pods.Items); i++ { | ||
pod := &(pods.Items[i]) | ||
m[pod.Namespace] = append(m[pod.Namespace], pod) | ||
} | ||
return m | ||
} | ||
|
||
func groupByNodeName(pods *v1.PodList, filter podutil.FilterFunc) map[string][]*v1.Pod { | ||
m := make(map[string][]*v1.Pod) | ||
if filter == nil { | ||
filter = func(p *v1.Pod) bool { return true } | ||
} | ||
for i := 0; i < len(pods.Items); i++ { | ||
pod := &(pods.Items[i]) | ||
if filter(pod) { | ||
m[pod.Spec.NodeName] = append(m[pod.Spec.NodeName], pod) | ||
} | ||
} | ||
return m | ||
} | ||
|
||
func createNodeMap(nodes []*v1.Node) map[string]*v1.Node { | ||
m := make(map[string]*v1.Node, len(nodes)) | ||
for _, node := range nodes { | ||
m[node.GetName()] = node | ||
} | ||
return m | ||
} | ||
|
||
// checkPodsWithAntiAffinityExist checks if there are other pods on the node that the current pod cannot tolerate. | ||
func checkPodsWithAntiAffinityExist(pod *v1.Pod, pods []*v1.Pod) bool { | ||
func checkPodsWithAntiAffinityExist(pod *v1.Pod, pods map[string][]*v1.Pod, nodeMap map[string]*v1.Node) bool { | ||
affinity := pod.Spec.Affinity | ||
if affinity != nil && affinity.PodAntiAffinity != nil { | ||
for _, term := range getPodAntiAffinityTerms(affinity.PodAntiAffinity) { | ||
|
@@ -120,16 +178,52 @@ func checkPodsWithAntiAffinityExist(pod *v1.Pod, pods []*v1.Pod) bool { | |
klog.ErrorS(err, "Unable to convert LabelSelector into Selector") | ||
return false | ||
} | ||
for _, existingPod := range pods { | ||
if existingPod.Name != pod.Name && utils.PodMatchesTermsNamespaceAndSelector(existingPod, namespaces, selector) { | ||
return true | ||
for _, namespace := range namespaces.List() { | ||
for _, existingPod := range pods[namespace] { | ||
if existingPod.Name != pod.Name && utils.PodMatchesTermsNamespaceAndSelector(existingPod, namespaces, selector) { | ||
node, ok := nodeMap[pod.Spec.NodeName] | ||
if !ok { | ||
continue | ||
} | ||
nodeHavingExistingPod, ok := nodeMap[existingPod.Spec.NodeName] | ||
if !ok { | ||
continue | ||
} | ||
if hasSameLabelValue(node, nodeHavingExistingPod, term.TopologyKey) { | ||
klog.V(1).InfoS("Found Pods violating PodAntiAffinity", "pod to evicted", klog.KObj(pod)) | ||
return true | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
return false | ||
} | ||
|
||
func hasSameLabelValue(node1, node2 *v1.Node, key string) bool { | ||
if node1.Name == node2.Name { | ||
return true | ||
} | ||
node1Labels := node1.Labels | ||
if node1Labels == nil { | ||
return false | ||
} | ||
node2Labels := node2.Labels | ||
if node2Labels == nil { | ||
return false | ||
} | ||
value1, ok := node1Labels[key] | ||
if !ok { | ||
return false | ||
} | ||
value2, ok := node2Labels[key] | ||
if !ok { | ||
return false | ||
} | ||
return value1 == value2 | ||
} | ||
|
||
// getPodAntiAffinityTerms gets the antiaffinity terms for the given pod. | ||
func getPodAntiAffinityTerms(podAntiAffinity *v1.PodAntiAffinity) (terms []v1.PodAffinityTerm) { | ||
if podAntiAffinity != nil { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, I'm afraid that this code duplicating with following:
descheduler/pkg/descheduler/pod/pods.go
Lines 170 to 172 in 93a014e