Kubernetes 1.19: SIG Scheduling の変更内容

# はじめに
Kubernetes v1.19 がリリース:tada: されてから1ヶ月程経ちましたね！ みなさんv1.19は活用されているでしょうか！？ 少しリリースから時間が立ってしまいましたが、Kubernetes 1.19.0の[CHANGELOG](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.19.md) をベースにSIG Schedulingにおける変更内容について紹介します。

v1.19における変更で一番の注目はやはり__Scheduling Frameworkでの `PostFilter` 拡張点の新規導入__です。この拡張点を利用することで__Preemptionのロジックが自由にカスタマイズできるようになります。__

以前のkube-schedulerでは [Priority and Preemption](https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/)における Preemption(低優先度のPodを高優先度のPodをスケジュールするために停止)処理、つまりどの低優先度Podを犠牲にするか？、のロジックがscheduler内にほぼすべてハードコードされていました。このおかげで、scheduler policyを柔軟にチューニングしていても、Preemptionが発生すると、チューニングしたscheduler policyを考慮しない低優先度Podが犠牲となってしまい、その引き金となった高優先度Podは基本的にその犠牲となったPodのスケジュールされたnodeへスケジュールされる(保証はされない)ため、チューニングの効果が限定されてしまうという問題がありました。

`PostFilter`拡張点はSchedulerにおけるFilter(Podを配置可能なノードを選択する内部フェーズ)失敗時の調停フェーズをPluginとして拡張する機構を提供することで、これをより一般的な形で解決しています(ハードコードされていたpreemptionロジックはPostFilterプラグインとしてデフォルトで有効化されています)。これでforkせずにPreemptionロジックを変更できるようになりますね💪💪！

_私は以前からこの問題を認識していてKubeCon+CloudNativeCon 2019 NA(San Diego)にてSIG Schedulingのchairである[Huang-Wei](https://github.com/Huang-Wei), [ahg-g](https://github.com/ahg-g)とのディスカッションを通してPreemptionにおける犠牲Pod選択戦略のカスタマイズという[#85871](https://github.com/kubernetes/kubernetes/issues/85871)を提起させていただき、その後、SIG Schedulingコミュニティでの議論([#90025](https://github.com/kubernetes/kubernetes/issues/90025))を経て、`PostFilter`拡張点としてリリースされたものなので大変に嬉しく思っています。_

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

# What's New (新情報)

## KubeSchedulerConfiguration が beta へ

SIG Scheduling は `KubeSchedulerConfiguration` を Beta へ昇格しました。[`KubeSchedulerConfiguration`](https://kubernetes.io/docs/reference/scheduling/config/) 機能により kube-scheduler のアルゴリズムや特定の設定をチューニングできます。選択したスケジューリングフェーズの特定の機能（プラグインに含まれる）を簡単に有効化したり無効化したりすることができます。さらに、一つの kube-scheduler インスタンスから、プロファイルと呼ばれる異なる設定を提供することができます。Podは `.spec.schedulerName` フィールドでスケジュールしたいプロファイルを選択することができます。

:pencil: 古くは kube-schedulerの設定ファイルの `kind` だった `componentconfig/v1alpha1` でしたが、[v1.12で `kubescheduler.config.k8s.io/v1alpha1` となり](https://github.com/kubernetes/kubernetes/blob/v1.12.1/CHANGELOG-1.12.md#v1120)、[v1.18で `kubescheduler.config.k8s.io/v1alpha2`にバージョンアップ](https://github.com/kubernetes/kubernetes/blob/v1.18.1/CHANGELOG/CHANGELOG-1.18.md#v1180) しました。 この `v1alpha2` から 複数プロファイルがサポートされ、今回めでたく beta に昇格しました。 複数プロファイルを使うと、一つのkube-schedulerインスタンスで複数のスケジュール戦略をホストできます。複数プロファイルの詳細については [KEP-1451](https://github.com/kubernetes/enhancements/blob/master/keps/sig-scheduling/1451-multi-scheduling-profiles/README.md#user-stories) を参照してください。尚、 このbeta昇格に関する [Urgent Upgrade Notes（必ず一読してからアップグレードしなければならない事項）](#urgent-upgrade-notes%E5%BF%85%E3%81%9A%E4%B8%80%E8%AA%AD%E3%81%97%E3%81%A6%E3%81%8B%E3%82%89%E3%82%A2%E3%83%83%E3%83%97%E3%82%B0%E3%83%AC%E3%83%BC%E3%83%89%E3%81%97%E3%81%AA%E3%81%91%E3%82%8C%E3%81%B0%E3%81%AA%E3%82%89%E3%81%AA%E3%81%84%E4%BA%8B%E9%A0%85) もありますので要確認です。

:pencil: 複数プロファイルと複数スケジューラの違いって何？と思われるかもしれません。一番の大きな違いは、scheduler内部のキューをプロファイル横断で共有できる点だと個人的には思っています。 kube-schedulerでは [Priority and Preemption](https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/)機能をつかって、クラスタに空きがない場合でもPreemption(高Priority Podをスケジュールするために低Priority Podを停止)を行うことで高Priority Podをスケジュールすることができます。が、この機能は cross-scheduler preemptionとでも呼べる挙動となっています。つまり、 scheduler名が異なる Podも一律に preemption対象とされてしまいます。 これを効率的に機能させるためには「基本的に高 Priority Pod は低 Priority Pod よりも前にスケジュールしておく」必要があります。これを行わない場合、スケジュールされた低 Priority Pod がすぐに Preemption されるといった、無用な Preemption が起こる可能性があるからです。複数schedulerインスタンスをデプロイすると、それぞれのインスタンスがそれぞれのタイミングでスケジュールを行うので、無用なPreemptionが増えてしまいます。一方で、複数プロファイルを使えば、kube-scheduler内部のキューを複数プロファイルで共有できるため無用なPreemptionを効果的に減らすことができます。


## Storage capacity tracking

これまで、Kubernetesのスケジューラは、追加の永続ストレージがクラスタ内のどこでも利用可能且つ無限の容量をもっているという想定でした。
トポロジーの制約により前者には対応しましたが、しかし、今までのPod スケジューリングは、ストレージの残り容量が新しいPodをスタートさせるのに十分でない可能性があることを考慮していませんでした。
ストレージ容量のトラッキング(アルファ機能)は、CSIドライバー向けにストレージ容量をレポートするAPIを追加することで、KubernetesのスケジューラがPodの新しいノードを選択する際に、この情報を使えるようになりました。
この機能は、容量が制限されるLocal Volumeや他のVolumeタイプのダイナミックプロビジョニングをサポートするための、足がかりとして提供します。

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

- `kubescheduler.config.k8s.io/v1alpha2` から `kubescheduler.config.k8s.io/v1beta1` へアップグレードしてください。
  - `.bindTimeoutSeconds` は[profile](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.19.md#profiles)毎に設定できる`VolumeBinding` pluginの設定の一部となりました。
  - `.extenders` はAPI 標準を満たすように更新されています。 特に
    - `.extenders` は case-sentive に decodeされるようになります。全てのフィールドが対象です。
    - `.extenders[*].httpTimeout` は `metav1.Duration` 型になります。
    - `.extenders[*].enableHttps` は `.extenders[*].enableHTTPS` に変更になります。
- `RequestedToCapacityRatio` の設定は case sensitiveにdecodeされるようになります。全てのフィールドが対象です。
- `DefaultPodTopologySpread` [plugin](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.19.md#scheduling-plugins) は `SelectorSpread` という名前に変更になります。
- `Unreserve` 拡張点は Profile定義から削除されます。すべての `Reserve` pluginは `Unreserve` 呼び出しを実装するようになります。
- `.disablePreemption` は削除されました。 "DefaultPreemption" PostFilter pluginを無効にすることでpreemptionを無効にできます。([#91420](https://github.com/kubernetes/kubernetes/pull/91420), by [pancernik](https://github.com/pancernik)) [SIG Scheduling]


# Deprecation (非推奨)

- Schedulerのalpha機能である `ResourceLimitsPriorityFunction` はあまり利用されてないため削除されました。([#91420](https://github.com/kubernetes/kubernetes/pull/91420), by [pancernik](https://github.com/pancernik)) [SIG Scheduling]

# API Change（API の変更）

- schuler設定である`KubeSchedulerConfiguration`から`BindTimeoutSeconds`を削除。 ([#91580](https://github.com/kubernetes/kubernetes/pull/91580), by [cofyc](https://github.com/cofyc)) [SIG Scheduling and Testing]
- kubescheduler.config.k8s.io/v1alpha1 を削除。 ([#89298](https://github.com/kubernetes/kubernetes/pull/89298), by [gavinfish](https://github.com/gavinfish)) [SIG Scheduling]
- Reserve Pluginでreserveに失敗したらunreserveをtriggerする。 ([#92391](https://github.com/kubernetes/kubernetes/pull/92391), by [adtac](https://github.com/adtac)) [SIG Scheduling and Testing]
- scheduler pluginのUnreserve拡張点をReserve拡張点に統合。 ([#92200](https://github.com/kubernetes/kubernetes/pull/92200), by [adtac](https://github.com/adtac)) [SIG Scheduling and Testing]
- `NodeResourcesLeastAllocated` と `NodeResourcesMostAllocated` で CPUとMemoryのカスタムweightをサポート。  ([#90544](https://github.com/kubernetes/kubernetes/pull/90544), by [chendave](https://github.com/chendave)) [SIG Scheduling]
- scheduler component config APIのversion v1beta1に`PostFilter` タイプを追加。 ([#91547](https://github.com/kubernetes/kubernetes/pull/91547), by [Huang-Wei](https://github.com/Huang-Wei)) [SIG Scheduling]

- `RequestedToCapacityRatioArgs` エンコーディングをstrictに行う。 ([#91603](https://github.com/kubernetes/kubernetes/pull/91603), by [pancernik](https://github.com/pancernik)) [SIG Scheduling]
- `v1beta1` Scheduler `Extender` エンコーディングをcase-sensitiveに (`v1alpha1`/`v1alpha2`はcase-insensitiveだった), `httpTimeout`フィールドでdurationエンコーディングに(例えば1秒は `"1s"`), `v1alpha1`/`v1alpha2`では`enableHttps`フィールドだったのを`enableHTTPS`に名前を変更する。 ([#91625](https://github.com/kubernetes/kubernetes/pull/91625), by [pancernik](https://github.com/pancernik)) [SIG Scheduling]

# Feature （機能）

- これまでhard-codeされていたPod preemptionロジックを defaultpreemption pluginとして登録し、schedulerで有効化する。 ([#92049](https://github.com/kubernetes/kubernetes/pull/92049), by [Huang-Wei](https://github.com/Huang-Wei)) [SIG Scheduling and Testing]
- `PostFilter`拡張点をscheduler framwrokに新しく追加。Filter phase後にfilterの失敗を解決するために実行される。典型な実装とはpreeptionロジックがある。 ([#91314](https://github.com/kubernetes/kubernetes/pull/91314), by [Huang-Wei](https://github.com/Huang-Wei)) [SIG Scheduling and Testing]
- 詳細なscheduler scoring結果をverbose level 10で表示可能にする。 ([#89384](https://github.com/kubernetes/kubernetes/pull/89384), by [Huang-Wei](https://github.com/Huang-Wei)) [SIG Scheduling]
- DefaultPodTopologySpread feature gateの有効化でPodTopologySpreadを使う。この場合DefaultPodTopologySpread pluginは無効にする。 ([#91793](https://github.com/kubernetes/kubernetes/pull/91793), by [alculquicondor](https://github.com/alculquicondor)) [SIG Scheduling]
- より良いspreadingを実現するPodTopologySpreadingの新スコアリング([#90475](https://github.com/kubernetes/kubernetes/pull/90475), by [alculquicondor](https://github.com/alculquicondor)) [SIG Scheduling]
- PodTolerationRestriction: Error時にWhitelist Scopeを明示する。 ([#87582](https://github.com/kubernetes/kubernetes/pull/87582), by [mrueg](https://github.com/mrueg)) [SIG Scheduling]
- PodTopologySpreading で maxSkewが増加した際に差分をへらすようなScore。 ([#90820](https://github.com/kubernetes/kubernetes/pull/90820), by [alculquicondor](https://github.com/alculquicondor)) [SIG Scheduling]
- PodTopologySpread schduling ScoreのWeightを2倍に変更。 ([#91258](https://github.com/kubernetes/kubernetes/pull/91258), by [alculquicondor](https://github.com/alculquicondor)) [SIG Scheduling]
- scheduler plugin開発者が クラスタレベルのeventを記録するために利用できるように`EventRecorder()`を`FrameworkHandle` インターフェースにexposeする。 ([#92010](https://github.com/kubernetes/kubernetes/pull/92010), by [Huang-Wei](https://github.com/Huang-Wei)) [SIG Scheduling]
- 複数のイメージを持つpodのnode優先度を適切に判断するために、`ImageLocality` pluginの`maxThreshold`をpod内のイメージ数に比例させる。 ([#91138](https://github.com/kubernetes/kubernetes/pull/91138), by [chendave](https://github.com/chendave)) [SIG Scheduling]

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

- Podがスケジュールされているにもかかわらずanotation変更によって発生する不要なscheduling churnを回避する。 ([#90373](https://github.com/kubernetes/kubernetes/pull/90373), by [fabiokung](https://github.com/fabiokung)) [SIG Scheduling]
- requiredなaffinity termをもつ最初のPodをtopology keyを満たすノードにのみスケジュールする。 ([#91168](https://github.com/kubernetes/kubernetes/pull/91168), by [ahg-g](https://github.com/ahg-g)) [SIG Scheduling]
- nodeをそのnodeのpodよりも前に削除したときに発生するscheduler crashを修正。 ([#89908](https://github.com/kubernetes/kubernetes/pull/89908), by [alculquicondor](https://github.com/alculquicondor)) [SIG Scheduling]
- nodeの削除時にPodのnominatedNodeNameがクリアされない問題を修正。 ([#91750](https://github.com/kubernetes/kubernetes/pull/91750), by [Huang-Wei](https://github.com/Huang-Wei)) [SIG Scheduling and Testing]
- HA環境において、standby schedulerでAPI serverとの接続が切れている間にPodが削除&再作成され、その後そのstandby schedulerがmasterになった場合にscheduler cacheが壊れる問題を修正。([#91126](https://github.com/kubernetes/kubernetes/pull/91126), by [Huang-Wei](https://github.com/Huang-Wei)) [SIG Scheduling]
- schedule再試行時にPod Conditionの更新をスキップ。 ([#91252](https://github.com/kubernetes/kubernetes/pull/91252), by [alculquicondor](https://github.com/alculquicondor)) [SIG Scheduling]
- PolicyからCCへの移行を援助するため、Scheduler v1 Policy config または algorithm-provider設定を v1beta1 ComponentConfigに渡せるようにする。 ([#92531](https://github.com/kubernetes/kubernetes/pull/92531), by [damemi](https://github.com/damemi)) [SIG Scheduling]
- 利用可能なnodeが存在しない場合のScheduling失敗を```schedule_attempts_total```メトリックのunschedulableとして記録する。 ([#90989](https://github.com/kubernetes/kubernetes/pull/90989), by [ahg-g](https://github.com/ahg-g)) [SIG Scheduling]

# Other (その他の修正)

- filterされたnodeが１個以下のときにScheduler PreScore pluginを実行しないようにする。([#89370](https://github.com/kubernetes/kubernetes/pull/89370), by [ahg-g](https://github.com/ahg-g)) [SIG Scheduling]