Register and enable defaultpreemption plugin

- Enable defaultpreemption as a PostFilter plugin
- Remote legacy hard-coded preemption logic
This commit is contained in:
Wei Huang 2020-06-22 17:22:27 -07:00 committed by Wei Huang
parent f38ce5725a
commit d99cc01646
No known key found for this signature in database
GPG Key ID: BE5E9752F8B6E005
14 changed files with 111 additions and 35 deletions

View File

@ -124,6 +124,9 @@ profiles:
filter:
disabled:
- name: "*"
postFilter:
disabled:
- name: "*"
preScore:
disabled:
- name: "*"
@ -175,6 +178,9 @@ profiles:
{Name: "PodTopologySpread"},
{Name: "InterPodAffinity"},
},
"PostFilterPlugin": {
{Name: "DefaultPreemption"},
},
"PreScorePlugin": {
{Name: "InterPodAffinity"},
{Name: "PodTopologySpread"},
@ -221,16 +227,17 @@ profiles:
},
wantPlugins: map[string]map[string][]kubeschedulerconfig.Plugin{
"default-scheduler": {
"BindPlugin": {{Name: "DefaultBinder"}},
"FilterPlugin": {{Name: "NodeResourcesFit"}, {Name: "NodePorts"}},
"PreFilterPlugin": {{Name: "NodeResourcesFit"}, {Name: "NodePorts"}},
"PreScorePlugin": {{Name: "InterPodAffinity"}, {Name: "TaintToleration"}},
"QueueSortPlugin": {{Name: "PrioritySort"}},
"ScorePlugin": {{Name: "InterPodAffinity", Weight: 1}, {Name: "TaintToleration", Weight: 1}},
"ReservePlugin": {{Name: "VolumeBinding"}},
"UnreservePlugin": {{Name: "VolumeBinding"}},
"PreBindPlugin": {{Name: "VolumeBinding"}},
"PostBindPlugin": {{Name: "VolumeBinding"}},
"BindPlugin": {{Name: "DefaultBinder"}},
"FilterPlugin": {{Name: "NodeResourcesFit"}, {Name: "NodePorts"}},
"PreFilterPlugin": {{Name: "NodeResourcesFit"}, {Name: "NodePorts"}},
"PostFilterPlugin": {{Name: "DefaultPreemption"}},
"PreScorePlugin": {{Name: "InterPodAffinity"}, {Name: "TaintToleration"}},
"QueueSortPlugin": {{Name: "PrioritySort"}},
"ScorePlugin": {{Name: "InterPodAffinity", Weight: 1}, {Name: "TaintToleration", Weight: 1}},
"ReservePlugin": {{Name: "VolumeBinding"}},
"UnreservePlugin": {{Name: "VolumeBinding"}},
"PreBindPlugin": {{Name: "VolumeBinding"}},
"PostBindPlugin": {{Name: "VolumeBinding"}},
},
},
},
@ -307,6 +314,9 @@ profiles:
{Name: "PodTopologySpread"},
{Name: "InterPodAffinity"},
},
"PostFilterPlugin": {
{Name: "DefaultPreemption"},
},
"PreScorePlugin": {
{Name: "InterPodAffinity"},
{Name: "PodTopologySpread"},

View File

@ -15,6 +15,7 @@ go_library(
"//pkg/scheduler/apis/config:go_default_library",
"//pkg/scheduler/framework/plugins/defaultbinder:go_default_library",
"//pkg/scheduler/framework/plugins/defaultpodtopologyspread:go_default_library",
"//pkg/scheduler/framework/plugins/defaultpreemption:go_default_library",
"//pkg/scheduler/framework/plugins/imagelocality:go_default_library",
"//pkg/scheduler/framework/plugins/interpodaffinity:go_default_library",
"//pkg/scheduler/framework/plugins/nodeaffinity:go_default_library",
@ -44,6 +45,7 @@ go_test(
"//pkg/scheduler/apis/config:go_default_library",
"//pkg/scheduler/framework/plugins/defaultbinder:go_default_library",
"//pkg/scheduler/framework/plugins/defaultpodtopologyspread:go_default_library",
"//pkg/scheduler/framework/plugins/defaultpreemption:go_default_library",
"//pkg/scheduler/framework/plugins/imagelocality:go_default_library",
"//pkg/scheduler/framework/plugins/interpodaffinity:go_default_library",
"//pkg/scheduler/framework/plugins/nodeaffinity:go_default_library",

View File

@ -26,6 +26,7 @@ import (
schedulerapi "k8s.io/kubernetes/pkg/scheduler/apis/config"
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/defaultbinder"
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/defaultpodtopologyspread"
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/defaultpreemption"
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/imagelocality"
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/interpodaffinity"
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodeaffinity"
@ -109,6 +110,11 @@ func getDefaultConfig() *schedulerapi.Plugins {
{Name: interpodaffinity.Name},
},
},
PostFilter: &schedulerapi.PluginSet{
Enabled: []schedulerapi.Plugin{
{Name: defaultpreemption.Name},
},
},
PreScore: &schedulerapi.PluginSet{
Enabled: []schedulerapi.Plugin{
{Name: interpodaffinity.Name},

View File

@ -21,6 +21,7 @@ import (
"github.com/google/go-cmp/cmp"
"k8s.io/component-base/featuregate"
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/defaultpreemption"
utilfeature "k8s.io/apiserver/pkg/util/feature"
featuregatetesting "k8s.io/component-base/featuregate/testing"
@ -80,6 +81,11 @@ func TestClusterAutoscalerProvider(t *testing.T) {
{Name: interpodaffinity.Name},
},
},
PostFilter: &schedulerapi.PluginSet{
Enabled: []schedulerapi.Plugin{
{Name: defaultpreemption.Name},
},
},
PreScore: &schedulerapi.PluginSet{
Enabled: []schedulerapi.Plugin{
{Name: interpodaffinity.Name},
@ -177,6 +183,11 @@ func TestApplyFeatureGates(t *testing.T) {
{Name: interpodaffinity.Name},
},
},
PostFilter: &schedulerapi.PluginSet{
Enabled: []schedulerapi.Plugin{
{Name: defaultpreemption.Name},
},
},
PreScore: &schedulerapi.PluginSet{
Enabled: []schedulerapi.Plugin{
{Name: interpodaffinity.Name},
@ -262,6 +273,11 @@ func TestApplyFeatureGates(t *testing.T) {
{Name: interpodaffinity.Name},
},
},
PostFilter: &schedulerapi.PluginSet{
Enabled: []schedulerapi.Plugin{
{Name: defaultpreemption.Name},
},
},
PreScore: &schedulerapi.PluginSet{
Enabled: []schedulerapi.Plugin{
{Name: interpodaffinity.Name},

View File

@ -1414,6 +1414,9 @@ func TestAlgorithmProviderCompatibility(t *testing.T) {
{Name: "PodTopologySpread"},
{Name: "InterPodAffinity"},
},
"PostFilterPlugin": {
{Name: "DefaultPreemption"},
},
"PreScorePlugin": {
{Name: "InterPodAffinity"},
{Name: "PodTopologySpread"},
@ -1483,6 +1486,9 @@ func TestAlgorithmProviderCompatibility(t *testing.T) {
{Name: "PodTopologySpread"},
{Name: "InterPodAffinity"},
},
"PostFilterPlugin": {
{Name: "DefaultPreemption"},
},
"PreScorePlugin": {
{Name: "InterPodAffinity"},
{Name: "PodTopologySpread"},
@ -1572,6 +1578,9 @@ func TestPluginsConfigurationCompatibility(t *testing.T) {
{Name: "PodTopologySpread"},
{Name: "InterPodAffinity"},
},
"PostFilterPlugin": {
{Name: "DefaultPreemption"},
},
"PreScorePlugin": {
{Name: "InterPodAffinity"},
{Name: "PodTopologySpread"},
@ -1771,6 +1780,11 @@ func TestPluginsConfigurationCompatibility(t *testing.T) {
{Name: "PodTopologySpread"},
},
},
PostFilter: &config.PluginSet{
Disabled: []config.Plugin{
{Name: "DefaultPreemption"},
},
},
PreScore: &config.PluginSet{
Disabled: []config.Plugin{
{Name: "InterPodAffinity"},
@ -1917,6 +1931,9 @@ func TestPluginsConfigurationCompatibility(t *testing.T) {
{Name: "NodeResourcesFit"},
{Name: "NodeUnschedulable"},
},
"PostFilterPlugin": {
{Name: "DefaultPreemption"},
},
"PreScorePlugin": {
{Name: "TaintToleration"},
{Name: "DefaultPodTopologySpread"},

View File

@ -30,7 +30,6 @@ import (
coreinformers "k8s.io/client-go/informers/core/v1"
"k8s.io/client-go/tools/cache"
"k8s.io/kubernetes/pkg/features"
kubefeatures "k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/scheduler/internal/queue"
"k8s.io/kubernetes/pkg/scheduler/profile"
)
@ -467,11 +466,6 @@ func addAllEventHandlers(
AddFunc: sched.onStorageClassAdd,
},
)
// TODO(Huang-Wei): remove this hack when defaultpreemption plugin is enabled.
if utilfeature.DefaultFeatureGate.Enabled(kubefeatures.PodDisruptionBudget) {
informerFactory.Policy().V1beta1().PodDisruptionBudgets().Lister()
}
}
func nodeSchedulingPropertiesChange(newNode *v1.Node, oldNode *v1.Node) string {

View File

@ -12,6 +12,7 @@ go_library(
"//pkg/scheduler/apis/config:go_default_library",
"//pkg/scheduler/framework/plugins/defaultbinder:go_default_library",
"//pkg/scheduler/framework/plugins/defaultpodtopologyspread:go_default_library",
"//pkg/scheduler/framework/plugins/defaultpreemption:go_default_library",
"//pkg/scheduler/framework/plugins/imagelocality:go_default_library",
"//pkg/scheduler/framework/plugins/interpodaffinity:go_default_library",
"//pkg/scheduler/framework/plugins/nodeaffinity:go_default_library",

View File

@ -6,10 +6,13 @@ go_library(
importpath = "k8s.io/kubernetes/pkg/scheduler/framework/plugins/defaultpreemption",
visibility = ["//visibility:public"],
deps = [
"//pkg/features:go_default_library",
"//pkg/scheduler/core:go_default_library",
"//pkg/scheduler/framework/v1alpha1:go_default_library",
"//pkg/scheduler/metrics:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
],
)

View File

@ -18,11 +18,15 @@ package defaultpreemption
import (
"context"
"time"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
utilfeature "k8s.io/apiserver/pkg/util/feature"
kubefeatures "k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/scheduler/core"
framework "k8s.io/kubernetes/pkg/scheduler/framework/v1alpha1"
"k8s.io/kubernetes/pkg/scheduler/metrics"
)
const (
@ -45,11 +49,22 @@ func (pl *DefaultPreemption) Name() string {
// New initializes a new plugin and returns it.
func New(_ runtime.Object, fh framework.FrameworkHandle) (framework.Plugin, error) {
pl := DefaultPreemption{fh}
if utilfeature.DefaultFeatureGate.Enabled(kubefeatures.PodDisruptionBudget) {
// A hack to initialize pdbLister in sharedInformerFactory.
fh.SharedInformerFactory().Policy().V1beta1().PodDisruptionBudgets().Lister()
}
return &pl, nil
}
// PostFilter invoked at the postFilter extension point.
func (pl *DefaultPreemption) PostFilter(ctx context.Context, state *framework.CycleState, pod *v1.Pod, m framework.NodeToStatusMap) (*framework.PostFilterResult, *framework.Status) {
preemptionStartTime := time.Now()
defer func() {
metrics.PreemptionAttempts.Inc()
metrics.SchedulingAlgorithmPreemptionEvaluationDuration.Observe(metrics.SinceInSeconds(preemptionStartTime))
metrics.DeprecatedSchedulingDuration.WithLabelValues(metrics.PreemptionEvaluation).Observe(metrics.SinceInSeconds(preemptionStartTime))
}()
nnn, err := core.Preempt(ctx, pl.fh, state, pod, m)
if err != nil {
return nil, framework.NewStatus(framework.Error, err.Error())

View File

@ -19,6 +19,7 @@ package plugins
import (
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/defaultbinder"
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/defaultpodtopologyspread"
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/defaultpreemption"
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/imagelocality"
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/interpodaffinity"
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodeaffinity"
@ -71,5 +72,6 @@ func NewInTreeRegistry() runtime.Registry {
serviceaffinity.Name: serviceaffinity.New,
queuesort.Name: queuesort.New,
defaultbinder.Name: defaultbinder.New,
defaultpreemption.Name: defaultpreemption.New,
}
}

View File

@ -525,7 +525,12 @@ func (f *frameworkImpl) runFilterPlugin(ctx context.Context, pl framework.Filter
// RunPostFilterPlugins runs the set of configured PostFilter plugins until the first
// Success or Error is met, otherwise continues to execute all plugins.
func (f *frameworkImpl) RunPostFilterPlugins(ctx context.Context, state *framework.CycleState, pod *v1.Pod, filteredNodeStatusMap framework.NodeToStatusMap) (*framework.PostFilterResult, *framework.Status) {
func (f *frameworkImpl) RunPostFilterPlugins(ctx context.Context, state *framework.CycleState, pod *v1.Pod, filteredNodeStatusMap framework.NodeToStatusMap) (_ *framework.PostFilterResult, status *framework.Status) {
startTime := time.Now()
defer func() {
metrics.FrameworkExtensionPointDuration.WithLabelValues(postFilter, status.Code().String()).Observe(metrics.SinceInSeconds(startTime))
}()
statuses := make(framework.PluginToStatus)
for _, pl := range f.postFilterPlugins {
r, s := f.runPostFilterPlugin(ctx, pl, state, pod, filteredNodeStatusMap)
@ -537,6 +542,7 @@ func (f *frameworkImpl) RunPostFilterPlugins(ctx context.Context, state *framewo
}
statuses[pl.Name()] = s
}
return nil, statuses.Merge()
}
@ -936,6 +942,11 @@ func (f *frameworkImpl) HasFilterPlugins() bool {
return len(f.filterPlugins) > 0
}
// HasPostFilterPlugins returns true if at least one postFilter plugin is defined.
func (f *frameworkImpl) HasPostFilterPlugins() bool {
return len(f.postFilterPlugins) > 0
}
// HasScorePlugins returns true if at least one score plugin is defined.
func (f *frameworkImpl) HasScorePlugins() bool {
return len(f.scorePlugins) > 0

View File

@ -481,6 +481,9 @@ type Framework interface {
// HasFilterPlugins returns true if at least one filter plugin is defined.
HasFilterPlugins() bool
// HasPostFilterPlugins returns true if at least one postFilter plugin is defined.
HasPostFilterPlugins() bool
// HasScorePlugins returns true if at least one score plugin is defined.
HasScorePlugins() bool

View File

@ -481,17 +481,10 @@ func (sched *Scheduler) scheduleOne(ctx context.Context) {
// into the resources that were preempted, but this is harmless.
nominatedNode := ""
if fitError, ok := err.(*core.FitError); ok {
if sched.DisablePreemption {
if sched.DisablePreemption || !prof.HasPostFilterPlugins() {
klog.V(3).Infof("Pod priority feature is not enabled or preemption is disabled by scheduler configuration." +
" No preemption is performed.")
} else {
preemptionStartTime := time.Now()
// TODO(Huang-Wei): implement the preemption logic as a PostFilter plugin.
nominatedNode, _ = core.Preempt(schedulingCycleCtx, prof, state, pod, fitError.FilteredNodesStatuses)
metrics.PreemptionAttempts.Inc()
metrics.SchedulingAlgorithmPreemptionEvaluationDuration.Observe(metrics.SinceInSeconds(preemptionStartTime))
metrics.DeprecatedSchedulingDuration.WithLabelValues(metrics.PreemptionEvaluation).Observe(metrics.SinceInSeconds(preemptionStartTime))
// Run PostFilter plugins to try to make the pod schedulable in a future scheduling cycle.
result, status := prof.RunPostFilterPlugins(ctx, state, pod, fitError.FilteredNodesStatuses)
if status.Code() == framework.Error {

View File

@ -601,19 +601,17 @@ func TestPostFilterPlugin(t *testing.T) {
expectPostFilterNumCalled: 0,
},
{
name: "Filter failed and PostFilter passed",
rejectFilter: true,
rejectPostFilter: false,
// TODO: change to <numNodes * 2> when the hard-coded preemption logic is removed.
expectFilterNumCalled: numNodes * 3,
name: "Filter failed and PostFilter passed",
rejectFilter: true,
rejectPostFilter: false,
expectFilterNumCalled: numNodes * 2,
expectPostFilterNumCalled: 1,
},
{
name: "Filter failed and PostFilter failed",
rejectFilter: true,
rejectPostFilter: true,
// TODO: change to <numNodes * 2> when the hard-coded preemption logic is removed.
expectFilterNumCalled: numNodes * 3,
name: "Filter failed and PostFilter failed",
rejectFilter: true,
rejectPostFilter: true,
expectFilterNumCalled: numNodes * 2,
expectPostFilterNumCalled: 1,
},
}
@ -645,6 +643,11 @@ func TestPostFilterPlugin(t *testing.T) {
Enabled: []schedulerconfig.Plugin{
{Name: postfilterPluginName},
},
// Need to disable default in-tree PostFilter plugins, as they will
// call RunFilterPlugins and hence impact the "numFilterCalled".
Disabled: []schedulerconfig.Plugin{
{Name: "*"},
},
},
},
}