Kubernetes 1.22: SIG Scheduling の変更内容

# はじめに

Kubernetes 1.22がリリースされましたね :tada:

今回もKubernetes v1.22の[CHANGELOG](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.22.md#v1220)をベースにSIG Schedulingに関する機能について紹介していきます。

- [Kubernetes 1.21: SIG Scheduling の変更内容](https://qiita.com/everpeace/items/084da032a83c81bb887a)
- [Kubernetes 1.20: SIG Scheduling の変更内容](https://qiita.com/everpeace/items/c2babe4f83ce31c41d06)

## 所感

v1.22では大きな機能追加はなく改善とバグ修正がメインとなっています。

- Score Pluginにおけるextended resource(GPU等)を考慮した改善
  - schedulerは空き容量に応じてschedule可能なNodeのscoreを計算して最適なNodeを選択しますが、 `NodeResources{LeastAllocated, MostAllocated, RequestedToCapacityRatio, BalancedAllocation}`といった典型的なnode score pluginでのGPU等のextended resourceの考慮が改善されました。
- [Scheduling Framework](https://kubernetes.io/docs/concepts/scheduling-eviction/scheduling-framework/)の機能拡充
  - SchedulerのComponentConfigで指定された`kubeconfig`がOut-of-tree pluginから利用可能に
  - Pluginから明示的にPodをBackoffQueue→ActiveQueueに移動させられることが可能に
  - PluginでScheduler初期化時のevent handlerを登録できることが可能に
  - 等、Pluginで実装できる範囲が広がりより柔軟なPlugin実装が可能になっています。
- kube-schedulerのComponentConfig `v1beta2`
  - 新しいVersionのComponentConfigですが、apiが大きく変わっているわけではなく、pluginのdeprecation/新規追加が主な目的です。
  - (追加)`NodeResourcesFit`という新しいpluginが導入され、`NodeResourcesLeastAllocated, NodeResourcesMostAllocated, RequestedToCapacityRatio`と別々のpluginで実装されていたものが統合されました。これらの相反するポリシーをユーザが誤って設定することがなくなってより安全な設定が可能になっています。
  - (deprecation) `NodeResourcesLeastAllocated, NodeResourcesMostAllocated, RequestedToCapacityRatio, NodeLabel, ServiceAffinity, NodePreferAvoidPods` pluginがdeprecatedになり、 `v1beta1`では利用できなくなっています。

> 下記 :pencil: がついた文章は、CHANGELOGの公式内容ではなく筆者の補足です。

# What's New (新情報)

# Urgent Upgrade Notes（必ず一読してからアップグレードしなければならない事項）

- Scheduler内の`CycleState`の`Read()`,`Write()`関数の内部でread/writeロックを取得するようになりました。 その結果`Lock()`, `Unlock()`関数が削除されました。Scheduler Plugin開発者は`CycleState#Lock()`, `CycleState#Unlock()`の呼び出しを除去して、スレッドセーフな`Read()`, `Write()`を呼び出すように変更する必要があります。([#101542](https://github.com/kubernetes/kubernetes/pull/101542), [@Huang-Wei](https://github.com/Huang-Wei))


# Deprecation (非推奨)

- `kube-scheduler`から既にdeprecatedだった`--hard-pod-affinity-symmetric-weight`, `--scheduler-name`が削除されました。 これらのパラメータを設定するには代わりに`ComponentConfig`を利用してください。([#102805](https://github.com/kubernetes/kubernetes/pull/102805), [@ahg-g](https://github.com/ahg-g))

# API Change （API の変更）

- `NodeResourcesLeastAllocated`,`NodeResourcesMostAllocated`,`RequestedToCapacityRatio`pluginが`v1beta2`でdeprecatedとなり、新しい`NodeResourcesFit`score extentionにマージされました。 `v1beta1`ではこれら3つのpluginは利用可能ですが、`NodeResourcesFit`pluginと同時には利用できません。([#101822](https://github.com/kubernetes/kubernetes/pull/101822), [@yuzhiquan](https://github.com/yuzhiquan))

:pencil: [KEP-2458: Resource Fit Scoring Strategy](https://github.com/kubernetes/enhancements/tree/master/keps/sig-scheduling/2458-node-resource-score-strategy)で提案されたものです。これら3つのscore pluginはお互いに相反する戦略を実装しているため、これらは同時に有効化されるべきではないにもかかわらず、個別のpluginとして提供されているため、同時に有効化することが可能となっていました。この変更にともなって各戦略は下記のように`NodeResourcesFit`pluginの`scoringStragey`というplugin argsで指定するようになりました。詳細な設定項目は[こちら](https://github.com/kubernetes/kubernetes/blob/v1.22.0/staging/src/k8s.io/kube-scheduler/config/v1beta2/types_pluginargs.go#L59-L77)を参照ください。また、deprecatedされたpluginは`v1beta1`でしか設定できなくなっています。
<details><summary>:pencil:設定例</summary><div>

```yaml
apiVersion: kubescheduler.config.k8s.io/v1beta2
kind: KubeSchedulerConfiguration
profiles:
- schedulerName: my-schedler
  plugins: ...
  pluginConfig:
  - name: NodeResourcesFit
    args:
      ignoredResources: [ "some-special/device" ]
      scoringStrategy:
        type: LeastAllocated | MostAllocated | RequestedToCapacityRatio
        resources:
        - {"name": "cpu", "weight": 1}
        - {"name": "memory", "weight": 1}
```
</div></details>


- PersistentVolumesとPersistentVolumeCaimsにReadWriteOncePodアクセスモードを追加します。単一ノード上の単一Podへのボリュームアクセスを制限します。([#102028](https://github.com/kubernetes/kubernetes/pull/102028), [@chrishenzie](https://github.com/chrishenzie)) [SIG Apps, CLI, Node, Scheduling and Storage]

:pencil: これまでの`ReadWriteOnce`アクセスモードは、あくまで1つのノードからRead/Writeでマウントする仕様でした。今回追加された`ReadWriteOncePod`により、1 PodからのみRead/Write可能になります。[Kubernetes 1.22: SIG Storageの変更内容](https://qiita.com/ysakashita/items/c54b4107524f45effd4a#api%E5%91%A8%E3%82%8A%E3%81%AE%E5%A4%89%E6%9B%B4-api-change) でも解説されていますのでそちらを御覧ください。

- `ComponentConfig`の`v1beta2`では明示的に有効したpluginはdefaultの設定よりも優先されるようになります。これによって、デフォルトで有効なpluginの設定を変更する場合にdisableする必要がなくなります。([#99582](https://github.com/kubernetes/kubernetes/pull/99582), [@chendave](https://github.com/chendave))

:pencil: 書かれているとおりですが、`v1beta1`では、defaultプラグインの設定を変更する場合には一旦`disable`してから`enable`しなけれいけない、といいう、ユーザにとってわかりにくい挙動だったのが改善されました。
<details><summary>:pencil:設定例</summary><div>

```yaml
# v1beta1ではわざわざdisableしないと設定が有効にならない
apiVersion: kubescheduler.config.k8s.io/v1beta1
kind: KubeSchedulerConfiguration
profiles:
- schedulerName: my-scheduler
  plugins:
    score:
      # NodeAffinity score pluginのweightを変更
      enabled:
      - name: NodeAffinity
        weight: 100
      disabled:
      - name: NodeAffinity
---
# v1beta2ではこれでOK
apiVersion: kubescheduler.config.k8s.io/v1beta1
kind: KubeSchedulerConfiguration
profiles:
- schedulerName: my-scheduler
  plugins:
    score:
      # NodeAffinity score pluginのweightを変更
      enabled:
      - name: NodeAffinity
        weight: 100
```
</div></details>

- `NodeResourcesBalancedAllocation`score pluginで、CPU、メモリ以外のGPU等のリソースを考慮する設定が可能になります。 ([#101946](https://github.com/kubernetes/kubernetes/pull/101946), https://github.com/chendave)

 <details><summary>:pencil:設定例</summary><div>

```yaml
apiVersion: kubescheduler.config.k8s.io/v1beta1
kind: KubeSchedulerConfiguration
profiles:
- schedulerName: my-scheduler
  plugins:
    score:
      enabled:
      - name: NodeResourcesBalancedAllocation
        weight: 1
  pluginConfig:
  - name: NodeResourcesBalancedAllocation
    args:
      resources:
        - name: cpu
       　　　　　　weight: 1
        - name: memory
          weight: 0
        - name: nvidia.com/gpu
          weight: 1
```
</div></details>

- `kube-scheduler`component configの `v1beta2` APIが利用可能になりました。それに伴って`NodeLabel, ServiceAffinity, NodePreferAvoidPods`の3つのpluginがdeprecatedになりました。 ([#99597](https://github.com/kubernetes/kubernetes/pull/99597), [@adtac](https://github.com/adtac))

:pencil: deprecatedされたpluginは`v1beta1`でしか設定できなくなります。　それぞれ　`NodeLabel`→`NodeAffinity`, `ServiceAffinity`→`InterPodAffinity`, `NodePreferAvoidPods`→Node Taint、で代用することが想定されています。これらのpluginを利用している場合にはwarning logが出力されます。このPRではこの3つのpluginがdeprecatedになっていますが、この他に上で取り上げた`NodeResourcesLeastAllocated`,`NodeResourcesMostAllocated`,`RequestedToCapacityRatio`pluginもdeprecatedにっており、v1.21で合計6個のpluginがdepreatedになっています。deprecatedなpluginの完全なリストは[こちら](https://kubernetes.io/docs/reference/scheduling/config/)を御覧ください。

- Pod Affinityにおける`NamespaceSelector`とそれに関する`CrossNamespaceAffinity`quota scopeがbetaになり、デフォルトで有効になりました。 ([#101496](https://github.com/kubernetes/kubernetes/pull/101496), [@ahg-g](https://github.com/ahg-g))
- 既にdeprecatedな`--algorithm-provider`フラグが`kube-scheduler`から削除されました。代わりに`ComponentConfig`のplugin setを定義するようにしてください。([#102239](https://github.com/kubernetes/kubernetes/pull/102239), [@Haleygo](https://github.com/Haleygo))


# Feature （機能）

- `LeastAllocated`, `MostAllocated`, `RequestedToCapacityRatio`pluginに設定されているextended resoruceは、そのリソースを要求していないPodではbypassされるようになります。([#103169](https://github.com/kubernetes/kubernetes/pull/103169), [@Huang-Wei](https://github.com/Huang-Wei))

:pencil: これらのプラグインでは、extended resource(ここではGPUを例に説明します)を考慮するように設定が可能ですが、以前は、考慮するように設定してしまうと、GPUを要求していないPodでも、Node ScoreにGPUの割当状況が反映されたスコアが計算されるようになっていました。これだと、[#103383](https://github.com/kubernetes/kubernetes/issues/102154)で報告されているように、GPU 要求していないPodがGPUノードに割り当てられやすくなってしまい(GPUの割当状況がスコアに勘案されるため)、それによってGPUを要求するPodが将来的にスケジュールされにくくなってしまうという問題がありました。この機能が入ることで、GPUをPodが要求していないPodのNode ScoreではGPUの割当状況を計算しないようにbypassすることでこの状況が改善されるようになっています。

- Schedulerにいて、Plugin開発者がPodをactiveQに明示的に移動させることができるようになりました。([#103383](https://github.com/kubernetes/kubernetes/pull/103383), [@Huang-Wei](https://github.com/Huang-Wei))

:pencil: kube-schedulerではスケジュール可能なNodeが見つからないPodはscheduler内部のBackoffQueueにおかれてschedule試行の間隔が調整されています。これだと、Co-Scheduling等(aka Gang Scheduling)のユースケースでは、PodGroup内の全PodがActiveQueueに存在しない場合があり効率が悪くなってしまいます。この機能によって、Plugin開発者が、明示的にBackoffQueueからActiveQueueに強制的にPodを移動させられるようになるため、Co-Schedulingのようなユースケースで効率よくスケジューリングができるようになります。

- scheduler framework handleでkubeconfigがexposeされるようになります。これによってOut-of-tree pluginが容易にCRD inforemerを作れるようになります。([#100644](https://github.com/kubernetes/kubernetes/pull/100644), [@Huang-Wei](https://github.com/Huang-Wei)) [SIG Apps, Scheduling and Testing]

:pencil: これまでOut-of-tree pluginを実装する場合に、schedulerに設定されたkubeconfigが受け取れないため毎回pluginの設定で自分でkubeconfigパスを指定する必要があり煩雑だったのですが、この変更で安全にschedulerにセットされたconfigが受け取れるようになりました。地味ですがplugin開発者にとっては結構嬉しい変更です。

- `PreferNominatedNode ` がBetaに昇格しデフォルトで有効になります。([#102201](https://github.com/kubernetes/kubernetes/pull/102201), [@chendave](https://github.com/chendave))
- Schedulerにおいてevent handlerが動的に登録できるようになります。 ([#101394](https://github.com/kubernetes/kubernetes/pull/101394), [@Huang-Wei](https://github.com/Huang-Wei))

# Documentation

:pencil: ありません。

# Failing Test (失敗しているテスト)

:pencil: ありません。

# Bug or Regression （バグまたはリグレッション）

- scheduler内にphantomなpreemptor podが存在してしまうバグを修正しました。([#102498](https://github.com/kubernetes/kubernetes/pull/102498), [@Huang-Wei](https://github.com/Huang-Wei))

:pencil: このバグによって実際は空きがあるNodeにもかかわらずPodがスケジュールされない状況が発生してしまいます。この修正はv1.19以降のすべてのマイナーバージョンにbackportされています。これらのバージョンを利用されている場合は最新のマイナーバージョンへバージョンアップをおすすめします。

- `NodeResourcesMostAllocated`, `NodeResourcesBalancedAllocation`pluginで、nodeが `requests` を持たないコンテナが存在する場合のScore計算を修正しました。 この修正によって小規模なNodeで発生していしまう利用率が低くなってしまう状況を改善しています。([#102925](https://github.com/kubernetes/kubernetes/pull/102925), [@alculquicondor](https://github.com/alculquicondor))

:pencil: `requests` 節を持たないPodでは、小さなdefault値を与えてscoreを計算していましたが、これだと、小規模なNodeに大量の`requests`節を持たないPodがスケジュールされると、それらが積み上がってscheduleされない状況が発生していましたが、この修正ではそれが改善されています。この修正はv1.19以降のすべてのマイナーバージョンにbackportされています。これらのバージョンを利用されている場合は最新のマイナーバージョンへバージョンアップをおすすめします。

- Preemption時にscheduler extenderが呼ばれなかったバグを修正しました。([#103019](https://github.com/kubernetes/kubernetes/pull/103019), [@ordovicia](https://github.com/ordovicia))

:pencil: この修正はv1.20以降のすべてのマイナーバージョンにbackportされています。これらのバージョンを利用されている場合は最新のマイナーバージョンへバージョンアップをおすすめします。

- Pod全体ではなくpod statusのmerge patchを生成するように変更しました。([#103133](https://github.com/kubernetes/kubernetes/pull/103133), [@marwanad](https://github.com/marwanad)) 

:pencil: schedulerはschedule結果をPodに記録する際にPod全体のmerge patchを生成するようになっていましたが、[#101697](https://github.com/kubernetes/kubernetes/issues/101697)に報告されているように`imagePullSecrets: [{}]` のようなspecを含むPodで、mergeに失敗し続けてしまい、scheduleされないバグがありました。このPRでpod statusのみに絞ってmerge patchを変更することでこれを修正しています。この修正はv1.19以降のすべてのマイナーバージョンにbackportされています。これらのバージョンを利用されている場合は最新のマイナーバージョンへバージョンアップをおすすめします。

# Other (その他の修正)

:pencil: ありません。