mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-22 11:21:47 +00:00
scheduler framework: document how to make plugins configurable
Signed-off-by: Adhityaa Chandrasekar <adtac@google.com>
This commit is contained in:
parent
b9d2df810c
commit
3e7b2c0707
142
pkg/scheduler/framework/plugins/README.md
Normal file
142
pkg/scheduler/framework/plugins/README.md
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
# Scheduler Framework Plugins
|
||||||
|
|
||||||
|
## Creating a new in-tree plugin
|
||||||
|
|
||||||
|
Read [the docs](https://kubernetes.io/docs/concepts/scheduling-eviction/scheduling-framework/)
|
||||||
|
to understand the different extension points within the scheduling framework.
|
||||||
|
|
||||||
|
TODO(#95156): flesh this out a bit more.
|
||||||
|
|
||||||
|
## Adding plugin configuration parameters through `KubeSchedulerConfiguration`
|
||||||
|
|
||||||
|
You can give users the ability to configure parameters in scheduler plugins using
|
||||||
|
[`KubeSchedulerConfiguration`](https://kubernetes.io/docs/reference/scheduling/config/).
|
||||||
|
This section covers how you can add arguments to existing in-tree plugins [(example PR)](https://github.com/kubernetes/kubernetes/pull/94814).
|
||||||
|
Let's assume the plugin is called `FooPlugin` and we want to add an optional
|
||||||
|
integer parameter named `barParam`.
|
||||||
|
|
||||||
|
### Defining and registering the struct
|
||||||
|
|
||||||
|
First, we need to define a struct type named `FooPluginArgs` in
|
||||||
|
`pkg/scheduler/apis/config/types_pluginargs.go`, which is the representation of
|
||||||
|
the configuration parameters that is internal to the scheduler.
|
||||||
|
|
||||||
|
```go
|
||||||
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
|
|
||||||
|
type FooPluginArgs struct {
|
||||||
|
// metav1 is k8s.io/apimachinery/pkg/apis/meta/v1
|
||||||
|
metav1.TypeMeta
|
||||||
|
BarParam int32
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that we embed `k8s.io/apimachinery/pkg/apis/meta/v1.TypeMeta` to include
|
||||||
|
API metadata for [versioning and persistence](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#api-conventions).
|
||||||
|
We add the `+k8s:deepcopy-gen:interfaces` comment to [auto-generate a `DeepCopy` function](https://github.com/kubernetes/kubernetes/tree/master/staging/src/k8s.io/code-generator)
|
||||||
|
for the struct.
|
||||||
|
|
||||||
|
Similarly, define `FooPluginArgs` in `k8s.io/kube-scheduler/config/{version}/types_pluginargs.go`,
|
||||||
|
which is the versioned representation used in the `kube-scheduler` binary used
|
||||||
|
for deserialization. This time, however, in order to allow implicit default
|
||||||
|
values for arguments, the type of the struct's fields may be pointers; leaving
|
||||||
|
a parameter unspecified will set the pointer field to its zero value (nil),
|
||||||
|
which can be used to let the framework know that it must fill in the default
|
||||||
|
value. `BarParam` is of type `int32` and let's say we want a non-zero default
|
||||||
|
value for it:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
|
|
||||||
|
type FooPluginArgs struct {
|
||||||
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
BarParam *int32 `json:"barParam,omitempty"`
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
For each `types_pluginargs.go` addition, remember to register the type in the
|
||||||
|
corresponding `register.go`, which will allow the scheduler to recognize
|
||||||
|
`KubeSchedulerConfiguration` values at parse-time.
|
||||||
|
|
||||||
|
### Setting defaults
|
||||||
|
|
||||||
|
When a `KubeSchedulerConfiguration` object is parsed (happens in
|
||||||
|
`cmd/kube-scheduler/app/options/options.go`), the scheduler will convert from
|
||||||
|
the versioned type to the internal type, filling in the unspecified fields with
|
||||||
|
defaults. Speaking of defaults, define `SetDefaults_FooPluginArgs` in
|
||||||
|
`pkg/scheduler/apis/config/v1beta1/defaults.go` as follows:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// v1beta1 refers to k8s.io/kube-scheduler/config/v1beta1.
|
||||||
|
func SetDefaults_FooPluginArgs(obj *v1beta1.FooPluginArgs) {
|
||||||
|
if obj.BarParam == nil {
|
||||||
|
obj.BarParam = pointer.Int32Ptr(42)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Validating configuration at runtime
|
||||||
|
|
||||||
|
Next, we need to define validators to make sure the user's configuration and
|
||||||
|
your default values are valid. To do this, add something like this in
|
||||||
|
`pkg/scheduler/apis/config/validation/validation_pluginargs.go`:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// From here on, FooPluginArgs refers to the type defined in pkg/scheduler
|
||||||
|
// definition, not the kube-scheduler definition. We're dealing with
|
||||||
|
// post-default values.
|
||||||
|
func ValidateFooPluginArgs(args config.FooPluginArgs) error {
|
||||||
|
if args.BarParam < 0 && args.BarParam > 100 {
|
||||||
|
return fmt.Errorf("must be in the range [0, 100]")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Code generation
|
||||||
|
|
||||||
|
We have defined everything necessary to run code generation now. Remember to
|
||||||
|
commit all your changes (not sure why this is needed) and do a `make clean`
|
||||||
|
first. Then:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ cd $GOPATH/src/k8s.io/kubernetes
|
||||||
|
$ git add -A && git commit
|
||||||
|
$ make clean
|
||||||
|
$ ./hack/update-codegen.sh
|
||||||
|
$ make generated_files
|
||||||
|
```
|
||||||
|
|
||||||
|
This should automatically generate code to deep copy objects, convert between
|
||||||
|
different struct types, convert pointer types to raw types, and set defaults.
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
|
||||||
|
After code generation, go back and write tests for all of the changes you made
|
||||||
|
in the previous section:
|
||||||
|
|
||||||
|
- `pkg/scheduler/apis/config/v1beta1/defaults_test.go` to unit test the
|
||||||
|
defaults.
|
||||||
|
- `pkg/scheduler/apis/config/validation/validation_pluginargs_test.go` to unit
|
||||||
|
test the validator.
|
||||||
|
- `pkg/scheduler/apis/config/scheme/scheme_test.go` to test the whole pipeline
|
||||||
|
using a `KubeSchedulerConfiguration` definition.
|
||||||
|
|
||||||
|
### Receiving the arguments in the plugin
|
||||||
|
|
||||||
|
We can now finally receive `FooPluginArgs` in the plugin code. To do this,
|
||||||
|
modify the plugin's `New` method signature like so:
|
||||||
|
|
||||||
|
```go
|
||||||
|
func New(fpArgs runtime.Object, fh framework.FrameworkHandle) (framework.Plugin, error) {
|
||||||
|
// config.FooPluginArgs refers to the pkg/scheduler struct type definition.
|
||||||
|
args, ok := fpArgs.(*config.FooPluginArgs)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("got args of type %T, want *FooPluginArgs", fpArgs)
|
||||||
|
}
|
||||||
|
if err := validation.ValidateFooPluginArgs(*args); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Use args.BarParam as you like.
|
||||||
|
}
|
||||||
|
```
|
Loading…
Reference in New Issue
Block a user