mirror of https://github.com/k3s-io/k3s
Allow parametrization of RequestedToCapacityRatio priority function via policy config
parent
4684d5aac6
commit
98041d0925
|
@ -640,7 +640,17 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
||||||
{"name": "TaintTolerationPriority", "weight": 2},
|
{"name": "TaintTolerationPriority", "weight": 2},
|
||||||
{"name": "InterPodAffinityPriority", "weight": 2},
|
{"name": "InterPodAffinityPriority", "weight": 2},
|
||||||
{"name": "MostRequestedPriority", "weight": 2},
|
{"name": "MostRequestedPriority", "weight": 2},
|
||||||
{"name": "RequestedToCapacityRatioPriority", "weight": 2}
|
{
|
||||||
|
"name": "RequestedToCapacityRatioPriority",
|
||||||
|
"weight": 2,
|
||||||
|
"argument": {
|
||||||
|
"requestedToCapacityRatioArguments": {
|
||||||
|
"shape": [
|
||||||
|
{"utilization": 0, "score": 0},
|
||||||
|
{"utilization": 50, "score": 7}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}}
|
||||||
]
|
]
|
||||||
}`,
|
}`,
|
||||||
ExpectedPolicy: schedulerapi.Policy{
|
ExpectedPolicy: schedulerapi.Policy{
|
||||||
|
@ -676,7 +686,17 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
||||||
{Name: "TaintTolerationPriority", Weight: 2},
|
{Name: "TaintTolerationPriority", Weight: 2},
|
||||||
{Name: "InterPodAffinityPriority", Weight: 2},
|
{Name: "InterPodAffinityPriority", Weight: 2},
|
||||||
{Name: "MostRequestedPriority", Weight: 2},
|
{Name: "MostRequestedPriority", Weight: 2},
|
||||||
{Name: "RequestedToCapacityRatioPriority", Weight: 2},
|
{
|
||||||
|
Name: "RequestedToCapacityRatioPriority",
|
||||||
|
Weight: 2,
|
||||||
|
Argument: &schedulerapi.PriorityArgument{
|
||||||
|
RequestedToCapacityRatioArguments: &schedulerapi.RequestedToCapacityRatioArguments{
|
||||||
|
UtilizationShape: []schedulerapi.UtilizationShapePoint{
|
||||||
|
{Utilization: 0, Score: 0},
|
||||||
|
{Utilization: 50, Score: 7},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -100,10 +100,6 @@ func init() {
|
||||||
factory.RegisterPriorityFunction2("ImageLocalityPriority", priorities.ImageLocalityPriorityMap, nil, 1)
|
factory.RegisterPriorityFunction2("ImageLocalityPriority", priorities.ImageLocalityPriorityMap, nil, 1)
|
||||||
// Optional, cluster-autoscaler friendly priority function - give used nodes higher priority.
|
// Optional, cluster-autoscaler friendly priority function - give used nodes higher priority.
|
||||||
factory.RegisterPriorityFunction2("MostRequestedPriority", priorities.MostRequestedPriorityMap, nil, 1)
|
factory.RegisterPriorityFunction2("MostRequestedPriority", priorities.MostRequestedPriorityMap, nil, 1)
|
||||||
|
|
||||||
// TODO use RequestedToCapacityRatioResourceAllocationPriority(scoringFunctionShape functionShape)
|
|
||||||
// and build scoringFunctionShape based on configuration passed to scheduler on startup.
|
|
||||||
// What is proper way of passing configuration here? config file? startup flag?
|
|
||||||
factory.RegisterPriorityFunction2(
|
factory.RegisterPriorityFunction2(
|
||||||
"RequestedToCapacityRatioPriority",
|
"RequestedToCapacityRatioPriority",
|
||||||
priorities.RequestedToCapacityRatioResourceAllocationPriorityDefault().PriorityMap,
|
priorities.RequestedToCapacityRatioResourceAllocationPriorityDefault().PriorityMap,
|
||||||
|
|
|
@ -109,6 +109,8 @@ type PriorityArgument struct {
|
||||||
// The priority function that checks whether a particular node has a certain label
|
// The priority function that checks whether a particular node has a certain label
|
||||||
// defined or not, regardless of value
|
// defined or not, regardless of value
|
||||||
LabelPreference *LabelPreference
|
LabelPreference *LabelPreference
|
||||||
|
// The RequestedToCapacityRatio priority function is parametrized with function shape.
|
||||||
|
RequestedToCapacityRatioArguments *RequestedToCapacityRatioArguments
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServiceAffinity holds the parameters that are used to configure the corresponding predicate in scheduler policy configuration.
|
// ServiceAffinity holds the parameters that are used to configure the corresponding predicate in scheduler policy configuration.
|
||||||
|
@ -143,6 +145,20 @@ type LabelPreference struct {
|
||||||
Presence bool
|
Presence bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RequestedToCapacityRatioArguments holds arguments specific to RequestedToCapacityRatio priority function
|
||||||
|
type RequestedToCapacityRatioArguments struct {
|
||||||
|
// Array of point defining priority function shape
|
||||||
|
UtilizationShape []UtilizationShapePoint
|
||||||
|
}
|
||||||
|
|
||||||
|
// UtilizationShapePoint represents single point of priority function shape
|
||||||
|
type UtilizationShapePoint struct {
|
||||||
|
// Utilization (x axis). Valid values are 0 to 100. Fully utilized node maps to 100.
|
||||||
|
Utilization int
|
||||||
|
// Score assigned to given utilization (y axis). Valid values are 0 to 10.
|
||||||
|
Score int
|
||||||
|
}
|
||||||
|
|
||||||
// ExtenderManagedResource describes the arguments of extended resources
|
// ExtenderManagedResource describes the arguments of extended resources
|
||||||
// managed by an extender.
|
// managed by an extender.
|
||||||
type ExtenderManagedResource struct {
|
type ExtenderManagedResource struct {
|
||||||
|
|
|
@ -91,6 +91,8 @@ type PriorityArgument struct {
|
||||||
// The priority function that checks whether a particular node has a certain label
|
// The priority function that checks whether a particular node has a certain label
|
||||||
// defined or not, regardless of value
|
// defined or not, regardless of value
|
||||||
LabelPreference *LabelPreference `json:"labelPreference"`
|
LabelPreference *LabelPreference `json:"labelPreference"`
|
||||||
|
// The RequestedToCapacityRatio priority function is parametrized with function shape.
|
||||||
|
RequestedToCapacityRatioArguments *RequestedToCapacityRatioArguments `json:"requestedToCapacityRatioArguments"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServiceAffinity holds the parameters that are used to configure the corresponding predicate in scheduler policy configuration.
|
// ServiceAffinity holds the parameters that are used to configure the corresponding predicate in scheduler policy configuration.
|
||||||
|
@ -125,6 +127,20 @@ type LabelPreference struct {
|
||||||
Presence bool `json:"presence"`
|
Presence bool `json:"presence"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RequestedToCapacityRatioArguments holds arguments specific to RequestedToCapacityRatio priority function
|
||||||
|
type RequestedToCapacityRatioArguments struct {
|
||||||
|
// Array of point defining priority function shape
|
||||||
|
UtilizationShape []UtilizationShapePoint `json:"shape"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UtilizationShapePoint represents single point of priority function shape
|
||||||
|
type UtilizationShapePoint struct {
|
||||||
|
// Utilization (x axis). Valid values are 0 to 100. Fully utilized node maps to 100.
|
||||||
|
Utilization int `json:"utilization"`
|
||||||
|
// Score assigned to given utilization (y axis). Valid values are 0 to 10.
|
||||||
|
Score int `json:"score"`
|
||||||
|
}
|
||||||
|
|
||||||
// ExtenderManagedResource describes the arguments of extended resources
|
// ExtenderManagedResource describes the arguments of extended resources
|
||||||
// managed by an extender.
|
// managed by an extender.
|
||||||
type ExtenderManagedResource struct {
|
type ExtenderManagedResource struct {
|
||||||
|
|
|
@ -538,6 +538,15 @@ func (in *PriorityArgument) DeepCopyInto(out *PriorityArgument) {
|
||||||
**out = **in
|
**out = **in
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if in.RequestedToCapacityRatioArguments != nil {
|
||||||
|
in, out := &in.RequestedToCapacityRatioArguments, &out.RequestedToCapacityRatioArguments
|
||||||
|
if *in == nil {
|
||||||
|
*out = nil
|
||||||
|
} else {
|
||||||
|
*out = new(RequestedToCapacityRatioArguments)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -576,6 +585,27 @@ func (in *PriorityPolicy) DeepCopy() *PriorityPolicy {
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *RequestedToCapacityRatioArguments) DeepCopyInto(out *RequestedToCapacityRatioArguments) {
|
||||||
|
*out = *in
|
||||||
|
if in.UtilizationShape != nil {
|
||||||
|
in, out := &in.UtilizationShape, &out.UtilizationShape
|
||||||
|
*out = make([]UtilizationShapePoint, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RequestedToCapacityRatioArguments.
|
||||||
|
func (in *RequestedToCapacityRatioArguments) DeepCopy() *RequestedToCapacityRatioArguments {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(RequestedToCapacityRatioArguments)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *ServiceAffinity) DeepCopyInto(out *ServiceAffinity) {
|
func (in *ServiceAffinity) DeepCopyInto(out *ServiceAffinity) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
@ -613,6 +643,22 @@ func (in *ServiceAntiAffinity) DeepCopy() *ServiceAntiAffinity {
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *UtilizationShapePoint) DeepCopyInto(out *UtilizationShapePoint) {
|
||||||
|
*out = *in
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UtilizationShapePoint.
|
||||||
|
func (in *UtilizationShapePoint) DeepCopy() *UtilizationShapePoint {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(UtilizationShapePoint)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *Victims) DeepCopyInto(out *Victims) {
|
func (in *Victims) DeepCopyInto(out *Victims) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
|
|
@ -538,6 +538,15 @@ func (in *PriorityArgument) DeepCopyInto(out *PriorityArgument) {
|
||||||
**out = **in
|
**out = **in
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if in.RequestedToCapacityRatioArguments != nil {
|
||||||
|
in, out := &in.RequestedToCapacityRatioArguments, &out.RequestedToCapacityRatioArguments
|
||||||
|
if *in == nil {
|
||||||
|
*out = nil
|
||||||
|
} else {
|
||||||
|
*out = new(RequestedToCapacityRatioArguments)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -576,6 +585,27 @@ func (in *PriorityPolicy) DeepCopy() *PriorityPolicy {
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *RequestedToCapacityRatioArguments) DeepCopyInto(out *RequestedToCapacityRatioArguments) {
|
||||||
|
*out = *in
|
||||||
|
if in.UtilizationShape != nil {
|
||||||
|
in, out := &in.UtilizationShape, &out.UtilizationShape
|
||||||
|
*out = make([]UtilizationShapePoint, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RequestedToCapacityRatioArguments.
|
||||||
|
func (in *RequestedToCapacityRatioArguments) DeepCopy() *RequestedToCapacityRatioArguments {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(RequestedToCapacityRatioArguments)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *ServiceAffinity) DeepCopyInto(out *ServiceAffinity) {
|
func (in *ServiceAffinity) DeepCopyInto(out *ServiceAffinity) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
@ -613,6 +643,22 @@ func (in *ServiceAntiAffinity) DeepCopy() *ServiceAntiAffinity {
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *UtilizationShapePoint) DeepCopyInto(out *UtilizationShapePoint) {
|
||||||
|
*out = *in
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UtilizationShapePoint.
|
||||||
|
func (in *UtilizationShapePoint) DeepCopy() *UtilizationShapePoint {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(UtilizationShapePoint)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *Victims) DeepCopyInto(out *Victims) {
|
func (in *Victims) DeepCopyInto(out *Victims) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
|
|
@ -103,12 +103,14 @@ go_test(
|
||||||
"//pkg/api/testing:go_default_library",
|
"//pkg/api/testing:go_default_library",
|
||||||
"//pkg/scheduler:go_default_library",
|
"//pkg/scheduler:go_default_library",
|
||||||
"//pkg/scheduler/algorithm:go_default_library",
|
"//pkg/scheduler/algorithm:go_default_library",
|
||||||
|
"//pkg/scheduler/algorithm/priorities:go_default_library",
|
||||||
"//pkg/scheduler/api:go_default_library",
|
"//pkg/scheduler/api:go_default_library",
|
||||||
"//pkg/scheduler/api/latest:go_default_library",
|
"//pkg/scheduler/api/latest:go_default_library",
|
||||||
"//pkg/scheduler/cache:go_default_library",
|
"//pkg/scheduler/cache:go_default_library",
|
||||||
"//pkg/scheduler/core:go_default_library",
|
"//pkg/scheduler/core:go_default_library",
|
||||||
"//pkg/scheduler/testing:go_default_library",
|
"//pkg/scheduler/testing:go_default_library",
|
||||||
"//pkg/scheduler/util:go_default_library",
|
"//pkg/scheduler/util:go_default_library",
|
||||||
|
"//vendor/github.com/stretchr/testify/assert:go_default_library",
|
||||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||||
"//vendor/k8s.io/api/policy/v1beta1:go_default_library",
|
"//vendor/k8s.io/api/policy/v1beta1:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
|
|
|
@ -322,6 +322,15 @@ func RegisterCustomPriorityFunction(policy schedulerapi.PriorityPolicy) string {
|
||||||
},
|
},
|
||||||
Weight: policy.Weight,
|
Weight: policy.Weight,
|
||||||
}
|
}
|
||||||
|
} else if policy.Argument.RequestedToCapacityRatioArguments != nil {
|
||||||
|
pcf = &PriorityConfigFactory{
|
||||||
|
MapReduceFunction: func(args PluginFactoryArgs) (algorithm.PriorityMapFunction, algorithm.PriorityReduceFunction) {
|
||||||
|
scoringFunctionShape := buildScoringFunctionShapeFromRequestedToCapacityRatioArguments(policy.Argument.RequestedToCapacityRatioArguments)
|
||||||
|
p := priorities.RequestedToCapacityRatioResourceAllocationPriority(scoringFunctionShape)
|
||||||
|
return p.PriorityMap, nil
|
||||||
|
},
|
||||||
|
Weight: policy.Weight,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if existingPcf, ok := priorityFunctionMap[policy.Name]; ok {
|
} else if existingPcf, ok := priorityFunctionMap[policy.Name]; ok {
|
||||||
glog.V(2).Infof("Priority type %s already registered, reusing.", policy.Name)
|
glog.V(2).Infof("Priority type %s already registered, reusing.", policy.Name)
|
||||||
|
@ -340,6 +349,19 @@ func RegisterCustomPriorityFunction(policy schedulerapi.PriorityPolicy) string {
|
||||||
return RegisterPriorityConfigFactory(policy.Name, *pcf)
|
return RegisterPriorityConfigFactory(policy.Name, *pcf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func buildScoringFunctionShapeFromRequestedToCapacityRatioArguments(arguments *schedulerapi.RequestedToCapacityRatioArguments) priorities.FunctionShape {
|
||||||
|
n := len(arguments.UtilizationShape)
|
||||||
|
points := make([]priorities.FunctionShapePoint, 0, n)
|
||||||
|
for _, point := range arguments.UtilizationShape {
|
||||||
|
points = append(points, priorities.FunctionShapePoint{Utilization: int64(point.Utilization), Score: int64(point.Score)})
|
||||||
|
}
|
||||||
|
shape, err := priorities.NewFunctionShape(points)
|
||||||
|
if err != nil {
|
||||||
|
glog.Fatalf("invalid RequestedToCapacityRatioPriority arguments: %s", err.Error())
|
||||||
|
}
|
||||||
|
return shape
|
||||||
|
}
|
||||||
|
|
||||||
// IsPriorityFunctionRegistered is useful for testing providers.
|
// IsPriorityFunctionRegistered is useful for testing providers.
|
||||||
func IsPriorityFunctionRegistered(name string) bool {
|
func IsPriorityFunctionRegistered(name string) bool {
|
||||||
schedulerFactoryMutex.Lock()
|
schedulerFactoryMutex.Lock()
|
||||||
|
@ -494,6 +516,9 @@ func validatePriorityOrDie(priority schedulerapi.PriorityPolicy) {
|
||||||
if priority.Argument.LabelPreference != nil {
|
if priority.Argument.LabelPreference != nil {
|
||||||
numArgs++
|
numArgs++
|
||||||
}
|
}
|
||||||
|
if priority.Argument.RequestedToCapacityRatioArguments != nil {
|
||||||
|
numArgs++
|
||||||
|
}
|
||||||
if numArgs != 1 {
|
if numArgs != 1 {
|
||||||
glog.Fatalf("Exactly 1 priority argument is required, numArgs: %v, Priority: %s", numArgs, priority.Name)
|
glog.Fatalf("Exactly 1 priority argument is required, numArgs: %v, Priority: %s", numArgs, priority.Name)
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,9 @@ package factory
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/algorithm"
|
"k8s.io/kubernetes/pkg/scheduler/algorithm"
|
||||||
|
"k8s.io/kubernetes/pkg/scheduler/algorithm/priorities"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/api"
|
"k8s.io/kubernetes/pkg/scheduler/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -80,3 +82,19 @@ func TestValidatePriorityConfigOverFlow(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBuildScoringFunctionShapeFromRequestedToCapacityRatioArguments(t *testing.T) {
|
||||||
|
arguments := api.RequestedToCapacityRatioArguments{
|
||||||
|
UtilizationShape: []api.UtilizationShapePoint{
|
||||||
|
{Utilization: 10, Score: 1},
|
||||||
|
{Utilization: 30, Score: 5},
|
||||||
|
{Utilization: 70, Score: 2},
|
||||||
|
}}
|
||||||
|
builtShape := buildScoringFunctionShapeFromRequestedToCapacityRatioArguments(&arguments)
|
||||||
|
expectedShape, _ := priorities.NewFunctionShape([]priorities.FunctionShapePoint{
|
||||||
|
{Utilization: 10, Score: 1},
|
||||||
|
{Utilization: 30, Score: 5},
|
||||||
|
{Utilization: 70, Score: 2},
|
||||||
|
})
|
||||||
|
assert.Equal(t, expectedShape, builtShape)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue