Merge pull request #1991 from jkaniuk/custom-predicates

Optimize PredicateChecker for dedicated workloads
This commit is contained in:
Kubernetes Prow Robot 2019-05-13 06:30:18 -07:00 committed by GitHub
commit 8ee548d5bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 37 additions and 22 deletions

View File

@ -44,20 +44,23 @@ const (
affinityPredicateName = "MatchInterPodAffinity" affinityPredicateName = "MatchInterPodAffinity"
) )
type predicateInfo struct { // PredicateInfo assigns a name to a predicate
name string type PredicateInfo struct {
predicate predicates.FitPredicate Name string
Predicate predicates.FitPredicate
} }
// PredicateChecker checks whether all required predicates pass for given Pod and Node. // PredicateChecker checks whether all required predicates pass for given Pod and Node.
type PredicateChecker struct { type PredicateChecker struct {
predicates []predicateInfo predicates []PredicateInfo
predicateMetadataProducer predicates.PredicateMetadataProducer predicateMetadataProducer predicates.PredicateMetadataProducer
enableAffinityPredicate bool enableAffinityPredicate bool
} }
// We run some predicates first as they are cheap to check and they should be enough
// to fail predicates in most of our simulations (especially binpacking).
// There are no const arrays in Go, this is meant to be used as a const. // There are no const arrays in Go, this is meant to be used as a const.
var priorityPredicates = []string{"PodFitsResources", "GeneralPredicates", "PodToleratesNodeTaints"} var priorityPredicates = []string{"PodFitsResources", "PodToleratesNodeTaints", "GeneralPredicates", "ready"}
func init() { func init() {
// This results in filtering out some predicate functions registered by defaults.init() method. // This results in filtering out some predicate functions registered by defaults.init() method.
@ -141,31 +144,31 @@ func NewPredicateChecker(kubeClient kube_client.Interface, stop <-chan struct{})
for predicateName, predicateFunc := range sched.Config().Algorithm.Predicates() { for predicateName, predicateFunc := range sched.Config().Algorithm.Predicates() {
predicateMap[predicateName] = predicateFunc predicateMap[predicateName] = predicateFunc
} }
predicateMap["ready"] = isNodeReadyAndSchedulablePredicate // We want to make sure that some predicates are present to run them first
if err != nil { // as they are cheap to check and they should be enough to fail predicates
return nil, err
}
// We always want to have PodFitsResources as a first predicate we run
// as this is cheap to check and it should be enough to fail predicates
// in most of our simulations (especially binpacking). // in most of our simulations (especially binpacking).
predicateMap["ready"] = IsNodeReadyAndSchedulablePredicate
if _, found := predicateMap["PodFitsResources"]; !found { if _, found := predicateMap["PodFitsResources"]; !found {
predicateMap["PodFitsResources"] = predicates.PodFitsResources predicateMap["PodFitsResources"] = predicates.PodFitsResources
} }
if _, found := predicateMap["PodToleratesNodeTaints"]; !found {
predicateMap["PodToleratesNodeTaints"] = predicates.PodToleratesNodeTaints
}
predicateList := make([]predicateInfo, 0) predicateList := make([]PredicateInfo, len(predicateMap))
for _, predicateName := range priorityPredicates { for _, predicateName := range priorityPredicates {
if predicate, found := predicateMap[predicateName]; found { if predicate, found := predicateMap[predicateName]; found {
predicateList = append(predicateList, predicateInfo{name: predicateName, predicate: predicate}) predicateList = append(predicateList, PredicateInfo{Name: predicateName, Predicate: predicate})
delete(predicateMap, predicateName) delete(predicateMap, predicateName)
} }
} }
for predicateName, predicate := range predicateMap { for predicateName, predicate := range predicateMap {
predicateList = append(predicateList, predicateInfo{name: predicateName, predicate: predicate}) predicateList = append(predicateList, PredicateInfo{Name: predicateName, Predicate: predicate})
} }
for _, predInfo := range predicateList { for _, predInfo := range predicateList {
klog.V(1).Infof("Using predicate %s", predInfo.name) klog.V(1).Infof("Using predicate %s", predInfo.Name)
} }
informerFactory.Start(stop) informerFactory.Start(stop)
@ -182,7 +185,8 @@ func NewPredicateChecker(kubeClient kube_client.Interface, stop <-chan struct{})
}, nil }, nil
} }
func isNodeReadyAndSchedulablePredicate(pod *apiv1.Pod, meta predicates.PredicateMetadata, nodeInfo *schedulernodeinfo.NodeInfo) (bool, // IsNodeReadyAndSchedulablePredicate checks if node is ready.
func IsNodeReadyAndSchedulablePredicate(pod *apiv1.Pod, meta predicates.PredicateMetadata, nodeInfo *schedulernodeinfo.NodeInfo) (bool,
[]predicates.PredicateFailureReason, error) { []predicates.PredicateFailureReason, error) {
ready := kube_util.IsNodeReadyAndSchedulable(nodeInfo.Node()) ready := kube_util.IsNodeReadyAndSchedulable(nodeInfo.Node())
if !ready { if !ready {
@ -194,9 +198,9 @@ func isNodeReadyAndSchedulablePredicate(pod *apiv1.Pod, meta predicates.Predicat
// NewTestPredicateChecker builds test version of PredicateChecker. // NewTestPredicateChecker builds test version of PredicateChecker.
func NewTestPredicateChecker() *PredicateChecker { func NewTestPredicateChecker() *PredicateChecker {
return &PredicateChecker{ return &PredicateChecker{
predicates: []predicateInfo{ predicates: []PredicateInfo{
{name: "default", predicate: predicates.GeneralPredicates}, {Name: "default", Predicate: predicates.GeneralPredicates},
{name: "ready", predicate: isNodeReadyAndSchedulablePredicate}, {Name: "ready", Predicate: IsNodeReadyAndSchedulablePredicate},
}, },
predicateMetadataProducer: func(_ *apiv1.Pod, _ map[string]*schedulernodeinfo.NodeInfo) predicates.PredicateMetadata { predicateMetadataProducer: func(_ *apiv1.Pod, _ map[string]*schedulernodeinfo.NodeInfo) predicates.PredicateMetadata {
return nil return nil
@ -204,6 +208,17 @@ func NewTestPredicateChecker() *PredicateChecker {
} }
} }
// NewCustomTestPredicateChecker builds test version of PredicateChecker with additional predicates.
// Helps with benchmarking different ordering of predicates.
func NewCustomTestPredicateChecker(predicateInfos []PredicateInfo) *PredicateChecker {
return &PredicateChecker{
predicates: predicateInfos,
predicateMetadataProducer: func(_ *apiv1.Pod, _ map[string]*schedulernodeinfo.NodeInfo) predicates.PredicateMetadata {
return nil
},
}
}
// SetAffinityPredicateEnabled can be used to enable or disable checking MatchInterPodAffinity // SetAffinityPredicateEnabled can be used to enable or disable checking MatchInterPodAffinity
// predicate. This will cause incorrect CA behavior if there is at least a single pod in // predicate. This will cause incorrect CA behavior if there is at least a single pod in
// cluster using affinity/antiaffinity. However, checking affinity predicate is extremely // cluster using affinity/antiaffinity. However, checking affinity predicate is extremely
@ -321,15 +336,15 @@ func (pe *PredicateError) PredicateName() string {
func (p *PredicateChecker) CheckPredicates(pod *apiv1.Pod, predicateMetadata predicates.PredicateMetadata, nodeInfo *schedulernodeinfo.NodeInfo) *PredicateError { func (p *PredicateChecker) CheckPredicates(pod *apiv1.Pod, predicateMetadata predicates.PredicateMetadata, nodeInfo *schedulernodeinfo.NodeInfo) *PredicateError {
for _, predInfo := range p.predicates { for _, predInfo := range p.predicates {
// Skip affinity predicate if it has been disabled. // Skip affinity predicate if it has been disabled.
if !p.enableAffinityPredicate && predInfo.name == affinityPredicateName { if !p.enableAffinityPredicate && predInfo.Name == affinityPredicateName {
continue continue
} }
match, failureReasons, err := predInfo.predicate(pod, predicateMetadata, nodeInfo) match, failureReasons, err := predInfo.Predicate(pod, predicateMetadata, nodeInfo)
if err != nil || !match { if err != nil || !match {
return &PredicateError{ return &PredicateError{
predicateName: predInfo.name, predicateName: predInfo.Name,
failureReasons: failureReasons, failureReasons: failureReasons,
err: err, err: err,
} }