|
| 1 | +# Cluster Scheduler |
| 2 | + |
| 3 | +The _Cluster Scheduler_ that is part of the openMCP Operator is responsible for answering `ClusterRequest` resources by either creating new `Cluster` resources or referencing existing ones. |
| 4 | + |
| 5 | +## Configuration |
| 6 | + |
| 7 | +To disable the scheduler, make sure that `scheduler` is not part of the `--controllers` flag when running the binary. It is included by default. |
| 8 | + |
| 9 | +If not disabled, the scheduler requires a config that looks like this: |
| 10 | +```yaml |
| 11 | +scheduler: |
| 12 | + scope: Namespaced # optional |
| 13 | + strategy: Balanced # optional |
| 14 | + |
| 15 | + selectors: # optional |
| 16 | + clusters: # optional |
| 17 | + matchLabels: <...> # optional |
| 18 | + matchExpressions: <...> # optional |
| 19 | + requests: # optional |
| 20 | + matchLabels: <...> # optional |
| 21 | + matchExpressions: <...> # optional |
| 22 | + |
| 23 | + purposeMappings: |
| 24 | + mcp: |
| 25 | + selector: # optional |
| 26 | + matchLabels: <...> # optional |
| 27 | + matchExpressions: <...> # optional |
| 28 | + template: |
| 29 | + metadata: |
| 30 | + namespace: mcp-clusters |
| 31 | + spec: |
| 32 | + profile: gcp-workerless |
| 33 | + tenancy: Exclusive |
| 34 | + platform: |
| 35 | + template: |
| 36 | + spec: |
| 37 | + profile: gcp-large |
| 38 | + tenancy: Shared |
| 39 | + onboarding: |
| 40 | + template: |
| 41 | + spec: |
| 42 | + profile: gcp-workerless |
| 43 | + tenancy: Shared |
| 44 | + workload: |
| 45 | + tenancyCount: 20 |
| 46 | + template: |
| 47 | + metadata: |
| 48 | + namespace: workload-clusters |
| 49 | + spec: |
| 50 | + profile: gcp-small |
| 51 | + tenancy: Shared |
| 52 | +``` |
| 53 | +
|
| 54 | +The following fields can be specified inside the `scheduler` field: |
| 55 | +- `scope` _(optional, defaults to `Namespaced`)_ |
| 56 | + - Valid values: `Namespaced`, `Cluster` |
| 57 | + - Determines whether the scheduler takes `Cluster` resources in all namespaces into accounts or only in a specific one. |
| 58 | + - In `Namespaced` mode, only `Cluster` resources from a single namespace are taken into account when checking for existing clusters to schedule requests to. If the cluster template that corresponds to the purpose specified in the request has a `metadata.namespace` set, this namespace is used to check for `Cluster` resources and also to create new ones. If not, the namespace of the `ClusterRequest` resource is used instead. |
| 59 | + - In `Cluster` mode, the scheduler takes all clusters into account when trying to find existing clusters that can be reused. New clusters are still created in the namespace specified in the cluster template, or in the request's namespace, if the former one is not set. |
| 60 | +- `strategy` _(optional, defaults to `Balanced`)_ |
| 61 | + - Valid values: `Balanced`, `Random`, `Simple` |
| 62 | + - Determines how the scheduler chooses a cluster if multiple existing ones qualify for a request. |
| 63 | + - With the `Balanced` strategy, the scheduler chooses the cluster with the fewest requests pointing to it. In case of a tie, the first one is chosen. |
| 64 | + - With the `Random` strategy, a cluster is chosen randomly. |
| 65 | + - With the `Simple` strategy, the first cluster in the list (should be in alphabetical order) is chosen. |
| 66 | +- `selectors.clusters` _(optional)_ |
| 67 | + - A label selector that restricts which `Cluster` resources are evaluated by the scheduler. Clusters that don't match the selector are treated as if they didn't exist. |
| 68 | + - The selector syntax is the default k8s one, as it is used in `Deployment` resources, for example. |
| 69 | + - Validation of the configuration will fail if any of the cluster templates from the `purposeMappings` field does not match the selector - this would otherwise result in the scheduler creating clusters that it would be unable to find again later on. |
| 70 | + - Note that the scheduler might run into naming conflicts with existing `Cluster` resources that don't match the selectors. See below for further information on how new clusters are named. |
| 71 | + - Selectors specified in `selectors.clusters` apply to all `Cluster` resources, while selectors in `purposeMappings[*].selector` are only applied for that specific purpose. |
| 72 | +- `selectors.requests` _(optional)_ |
| 73 | + - A label selector that restricts which `ClusterRequest` resources are reconciled by the scheduler. Requests that don't match the selector are not reconciled. |
| 74 | + - The selector syntax is the default k8s one, as it is used in `Deployment` resources, for example. |
| 75 | +- `purposeMappings` |
| 76 | + - This is a map where each entry maps a purpose to a cluster template and some additional information. When a `ClusterRequest` is reconciled, its `spec.purpose` is looked up in this map and the result determines how existing clusters are evaluated and how new ones are created. |
| 77 | + - The structure for a mapping is explained below. |
| 78 | + |
| 79 | +Each value of a purpose mapping takes the following fields: |
| 80 | +- `template` |
| 81 | + - A `Cluster` template, consisting of `metadata` (optional) and `spec`. This is used when new clusters are created, but it is also partly evaluated when checking for existing ones. |
| 82 | + - `metadata.name` and `metadata.generateName` can be used to influence how newly created clusters are named. See below for further explanation on cluster naming. |
| 83 | + - `metadata.namespace` is the namespace in which newly created clusters for this purpose are created. If empty, the request's namespace is used instead. If the scheduler runs in `Namespaced` mode, this is also the only namespace that is evaluated when checking for existing clusters (again falling back to the request's namespace, if not specified). In `Cluster` mode, existing clusters are checked across all namespaces. |
| 84 | + - `metadata.labels` and `metadata.annotations` are simply passed to newly created clusters. If label selectors for clusters are specified, `metadata.labels` has to satisfy the selectors, otherwise the validation will fail. |
| 85 | + - `spec.profile` and `spec.tenancy` have to be set. The latter value determines whether the cluster is for the creating request exlusively (`Exclusive`) or whether other requests are allowed to point to the same cluster (`Shared`). |
| 86 | + - If `spec.purposes` does not contain the purpose this template is mapped to, it will be added during creation of the `Cluster`. |
| 87 | +- `tenancyCount` _(optional, defaults to `0`)_ |
| 88 | + - This value specifies how many requests may point to a cluster with this purpose. |
| 89 | + - If `template.spec.tenancy` is `Exclusive`, this value has to be `0` and does not have any effect. |
| 90 | + - If `template.spec.tenancy` is `Shared`, this value must be equal to or greater than `0`. |
| 91 | + - If greater than `0`, this is the amount of requests that may point to the same cluster. |
| 92 | + - A value of `1` behaves similar to an exclusive cluster, but the cluster is marked as shared and other requests may refer to it at a later point, if the value is increased or the scheduler logic is changed. |
| 93 | + - If `0`, the cluster is shared with an unlimited amount of requests that may refer to it. This basically means that there will ever be only one cluster for this purpose and all requests with this purpose will refer to this one cluster. |
| 94 | + - Note that 'one cluster' means 'within the boundaries specified by namespace and label selectors'. If the scheduler runs in `Namespaced` mode and the template does not specify a namespace, for example, one cluster per namespace will be created, not one in total. |
| 95 | +- `selector` _(optional)_ |
| 96 | + - A label selector that is used to filter `Cluster` resources when checking for existing clusters for this purpose. This is merged with any selectors from `selectors.clusters`. |
| 97 | + |
| 98 | +## Names and Namespaces of Clusters created by the Scheduler |
| 99 | + |
| 100 | +If the scheduler needs to create a new `Cluster` resource, because none of the existing ones fits the criteria for a `ClusterRequest`, it has to choose name and namespace for the `Cluster` resource. This is done according to the following logic: |
| 101 | + |
| 102 | +#### Namespace |
| 103 | + |
| 104 | +If the cluster template from the configuration for the requested purpose has `metadata.namespace` set, that is used as namespace. Otherwise, the cluster is created in the same namespace as the `ClusterRequest` that caused its creation. |
| 105 | + |
| 106 | +#### Name |
| 107 | + |
| 108 | +For clusters with `Exclusive` tenancy, or for `Shared` ones with a limited tenancy count, the scheduler uses `metadata.generateName` from the cluster template or defaults it to `<purpose>-`, if not set. |
| 109 | + |
| 110 | +For clusters with unlimited tenancy count, `metadata.generateName` takes precedence, if specified in the template, with `metadata.name` being evaluated second. If neither is specified, `<purpose>` is used as `metadata.name` (as there should be only one instance of this cluster in this namespace due to the unlimited tenancy count, there is no need to add a randomized suffix to the name). |
0 commit comments