github.com/kubewharf/katalyst-core@v0.5.3/pkg/agent/evictionmanager/rule/rule.go (about) 1 /* 2 Copyright 2022 The Katalyst Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package rule 18 19 import ( 20 "k8s.io/klog/v2" 21 kubelettypes "k8s.io/kubernetes/pkg/kubelet/types" 22 23 pkgconfig "github.com/kubewharf/katalyst-core/pkg/config" 24 "github.com/kubewharf/katalyst-core/pkg/config/generic" 25 "github.com/kubewharf/katalyst-core/pkg/util/general" 26 ) 27 28 var evictionScopePriority = map[string]int{ 29 EvictionScopeForce: 1, 30 EvictionScopeMemory: 2, 31 EvictionScopeCPU: 3, 32 } 33 34 type EvictionStrategy interface { 35 // CandidateSort defines the eviction priority among different EvictPods 36 CandidateSort(rpList RuledEvictPodList) 37 38 // CandidateValidate defines whether the given pod is permitted for 39 // eviction since some specific EvictPods should always keep running. 40 CandidateValidate(rp *RuledEvictPod) bool 41 } 42 43 type EvictionStrategyImpl struct { 44 conf *generic.GenericConfiguration 45 compares []general.CmpFunc 46 } 47 48 func NewEvictionStrategyImpl(conf *pkgconfig.Configuration) EvictionStrategy { 49 e := &EvictionStrategyImpl{ 50 conf: conf.GenericConfiguration, 51 } 52 53 // if any compare function reach out with a result, returns immediately 54 e.compares = []general.CmpFunc{ 55 e.CompareKatalystQoS, 56 e.ComparePriority, 57 e.CompareEvictionResource, 58 e.ComparePodName, 59 } 60 return e 61 } 62 63 // CandidateSort defines the sorting rules will be as below 64 // - katalyst QoS: none-reclaimed > reclaimed 65 // - pod priority 66 // - predefined resource priority: e.g. memory > cpu > ... 67 // - pod names 68 func (e *EvictionStrategyImpl) CandidateSort(rpList RuledEvictPodList) { 69 general.NewMultiSorter(e.compares...).Sort(rpList) 70 } 71 72 // CandidateValidate will try to filter out EvictPods from eviction 73 // - EvictPods with katalyst SystemQoS 74 // - EvictPods marked as critical 75 func (e *EvictionStrategyImpl) CandidateValidate(rp *RuledEvictPod) bool { 76 pod := rp.EvictPod.Pod 77 if pod == nil { 78 return false 79 } 80 81 if ok, err := e.conf.CheckSystemQoSForPod(pod); err != nil { 82 klog.Errorf("failed to get qos for pod %v, err: %v", pod.Name, err) 83 return true 84 } else if ok { 85 return false 86 } 87 88 if kubelettypes.IsCriticalPod(pod) { 89 return false 90 } 91 return true 92 } 93 94 // CompareKatalystQoS compares KatalystQoS for EvictPods, if we failed to 95 // parse qos level for a pod, we will consider it as none-reclaimed pod. 96 func (e *EvictionStrategyImpl) CompareKatalystQoS(s1, s2 interface{}) int { 97 return covertBoolSortCompareToIntSort(func(s1, s2 interface{}) bool { 98 c1, c2 := s1.(*RuledEvictPod), s2.(*RuledEvictPod) 99 100 p1Reclaimed, err := e.conf.CheckReclaimedQoSForPod(c1.Pod) 101 if err != nil { 102 klog.Errorf("failed to get qos for pod %v, err: %v", c1.Pod.Name, err) 103 p1Reclaimed = false 104 } 105 106 p2Reclaimed, err := e.conf.CheckReclaimedQoSForPod(c2.Pod) 107 if err != nil { 108 klog.Errorf("failed to get qos for pod %v, err: %v", c2.Pod.Name, err) 109 p2Reclaimed = false 110 } 111 112 return !p1Reclaimed && p2Reclaimed 113 }, s1, s2) 114 } 115 116 // ComparePriority compares pod priority for EvictPods, if any pod doesn't have 117 // nominated priority, it will always be inferior to those with priority nominated. 118 func (e *EvictionStrategyImpl) ComparePriority(s1, s2 interface{}) int { 119 return covertBoolSortCompareToIntSort(func(s1, s2 interface{}) bool { 120 c1, c2 := s1.(*RuledEvictPod), s2.(*RuledEvictPod) 121 122 if c1.Pod.Spec.Priority == nil { 123 return false 124 } 125 return c2.Pod.Spec.Priority == nil || *c1.Pod.Spec.Priority > *c2.Pod.Spec.Priority 126 }, s1, s2) 127 } 128 129 // CompareEvictionResource compares the eviction scope defined in each plugin 130 func (e *EvictionStrategyImpl) CompareEvictionResource(s1, s2 interface{}) int { 131 return covertBoolSortCompareToIntSort(func(s1, s2 interface{}) bool { 132 c1, c2 := s1.(*RuledEvictPod), s2.(*RuledEvictPod) 133 134 if _, ok := evictionScopePriority[c1.Scope]; !ok { 135 return false 136 } 137 if _, ok := evictionScopePriority[c2.Scope]; !ok { 138 return true 139 } 140 return evictionScopePriority[c2.Scope] > evictionScopePriority[c1.Scope] 141 }, s1, s2) 142 } 143 144 func (e *EvictionStrategyImpl) ComparePodName(s1, s2 interface{}) int { 145 return covertBoolSortCompareToIntSort(func(s1, s2 interface{}) bool { 146 c1, c2 := s1.(*RuledEvictPod), s2.(*RuledEvictPod) 147 148 return c1.Pod.Name > c2.Pod.Name 149 }, s1, s2) 150 } 151 152 // covertBoolSortCompareToIntSort converts the bool-based sorting 153 // function to int-based sorting function 154 func covertBoolSortCompareToIntSort(f func(s1, s2 interface{}) bool, s1, s2 interface{}) int { 155 if f(s1, s2) { 156 return -1 157 } else if f(s2, s1) { 158 return 1 159 } 160 return 0 161 }