Kubernetes 1.20: SIG Scheduling の変更内容

# はじめに

本ドキュメントでは、Kubernetes v1.20.0の[CHANGELOG](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.20.md)をベースにSIG Schedulingに関する機能について紹介します。

v1.20.0での変更はあまり多く有りません。主な変更をまとめると次のとおりです。
- [Default Pod Topology Spread を betaに昇格](#default-pod-topology-spread-to-beta)
- 大きめ(主観です)のBugFixが含まれており、すべてv1.18.x, v1.19.xにbackportされているので[Bug or Regression](https://qiita.com/everpeace/items/c2babe4f83ce31c41d06#bug-or-regression-%E3%83%90%E3%82%B0%E3%81%BE%E3%81%9F%E3%81%AF%E3%83%AA%E3%82%B0%E3%83%AC%E3%83%83%E3%82%B7%E3%83%A7%E3%83%B3)のsectionは確認すると良さそうです。

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

# What's New (新情報)

## Pod resource metrics

オンデマンドのメトリクスが `/metrics/resources` から利用できるようになりました。この機能を有効にすると実行中の Pod のリソースリクエストが取得できます。


:pencil: [Kubernetes 1.20: Metrics Changes と SIG Instrumentation の変更内容](https://qiita.com/watawuwu/items/ab5a0f11210d15cc6a86#pod-resource-metrics) で詳細に解説されているので参照してください。 簡単に解説すると、次のとおりです。

- Podは複数のContainer、複数にinitContainerから成るため、Pod全体としてのリソース要求量のメトリクスはこれまで出力されていませんでした。
- kube-state-metricsではコンテナ毎のリソース要求量のメトリクスを出力しているため、それらのメトリクスを使って計算することは可能でしたが、クエリが複雑になってしまう & 計算オーバーヘッドも大きいという課題がありました
  - しかも、正確に計算しようとすると、specで指定されているPod Overhead(Runtime ClassのOverhead)やEphemeral Volume, Hugepages等の要求量等も加味しなくてはいけません。
  - また、自分自信で記述したクエリ結果がschedulerが使っている値と一致している保証は自分で確保しなければならないため正確なキャパシティプランニングが困難な状態でした[^0]。
- このエンドポイントは、schedulerが算出したPodとしての要求量(`requests/limits`)を返してくれるため、メトリクス計算のオーバーヘッドを軽減でき、かつ信頼できるメトリクスを使えるようになります。
- 現時点ではfeature stateはalphaです。


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

:pencil: ありません。

# Deprecation (非推奨)

:pencil: ありません。

# API Change （API の変更）

- `PodTopologySpread` pluginで、明示的にk8sによるデフォルト制約 or ユーザ定義のデフォルト制約を指定する`defaultingType`パラメータが導入されました。([#95048](https://github.com/kubernetes/kubernetes/pull/95048), [@alculquicondor](https://github.com/alculquicondor)) [SIG Scheduling]
  - :pencil: この変更は [Default Pod Topology Spread を betaに昇格](#default-pod-topology-spread-to-beta)させる作業の一貫です。 betaに昇格させるとデフォルトでこの機能がenabledになるので、[scheduling profileを使ったCluster-levelのdefault spread constraintの指定](https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/#cluster-level-default-constraints)において、`defaultingType: "List|System"` プロパティを導入することで、空plugin設定の意図を明確に指定できるようになりました。互換性のためデフォルト値は`"List"`です。


# Feature （機能）

- <a name="default-pod-topology-spread-to-beta"></a>`DefaultPodTopologySpread` feature gateがBeta になりました。このfeature gateはデフォルトでenabledになります。([#95631](https://github.com/kubernetes/kubernetes/pull/95631), [@alculquicondor](https://github.com/alculquicondor)) [SIG Scheduling and Testing]
  - :pencil: Betaに昇格したので、[scheduling profileを使ったCluster-levelのdefault spread constraintの指定](https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/#cluster-level-default-constraints)の利用に際してfeature gateを明示的に設定する必要がなくなりました。
  - :pencil: 逆に言うと、`.spec.topologySpreadConstraints`を持たないPod[^1]は自動で[defaultのtopology spread constraint](https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/#internal-default-constraints)でspreadされるようになります。都合が悪い場合はfeature gateをdisableするか、[空のconstraintsを設定](https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/#internal-default-constraints)しましょう。
- デフォルトscheduler pluginの順序が変更され、 taintやnode affinityが使われている場合のschedule/preemption latencyが改善されます。([#95539](https://github.com/kubernetes/kubernetes/pull/95539), [@soulxu](https://github.com/soulxu)) [SIG Scheduling]
- `resourceVersion` が同一のPodのUpdateイベントを無視するようになりました。([#96071](https://github.com/kubernetes/kubernetes/pull/96071), [@Huang-Wei](https://github.com/Huang-Wei)) [SIG Scheduling]
- Scheduling Framework: `PostFilter`extention pointで利用可能な`PreemptionHandle`で`Run[Pre]ScorePlugins`関数が公開されるようになりました。([#93534](https://github.com/kubernetes/kubernetes/pull/93534), [@everpeace](https://github.com/everpeace)) [SIG Scheduling and Testing]
  - :pencil: 1.19から[Scheduling Framework](https://kubernetes.io/docs/concepts/scheduling-eviction/scheduling-framework/)において[PostFilter](https://kubernetes.io/docs/concepts/scheduling-eviction/scheduling-framework/#post-filter)というextention pointが導入されました。このextention pointは主にPreemptionロジックをカスタムするための導入です。[Preemption](https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/)は高優先度のPod(Preemptorと呼ばれます)をスケジュールするために、いくつかの低優先度のPod(Victimと呼ばれます)を選出し停止する、という処理を行います。その際に、scheduling profileで指定された Filter/Score 関数[^2]を呼び出したい場合があります。
      - Filter: Vicitmを選出するために、Victim候補を停止した後の仮想的なNodeに対してPreemptorがFitするかどうか？を判別するため
      - Score: 複数のNodeでVictim候補が選ばれた際に、どのNodeを最終的なVictimとして選出すべきか？つまりPreemptorをどのVictim Nodeにスケジュールすべきか？を評価するため
   
        です。1.19では[`PreemptionHandle`](https://github.com/kubernetes/kubernetes/blob/v1.20.0/pkg/scheduler/framework/interface.go#L551-L588)経由で公開されたいたのは`Filter`関数のみで、`Score`関数は公開されていませんでした。このため、Preemptor Podがvictim候補ノードを選ぶ際に設定されているscheduling profileと整合性の取れたNodeを選ぶことが困難でした[^3]。この変更は[`PreemptionHandle`](https://github.com/kubernetes/kubernetes/blob/v1.20.0/pkg/scheduler/framework/interface.go#L551-L588)で[`Score`関数](https://github.com/kubernetes/kubernetes/blob/v1.20.0/pkg/scheduler/framework/interface.go#L578-L581)を公開する変更です。この変更によって、ユーザの定義したscheduling profileとより整合性の取れたカスタム`PostFilter`Pluginの実装が可能になります。
- `DefaultPodTopologySpread`がenabledの場合、`SelectorSpreadPriority` pluginは`PodTopologySpread`pluginに変換されるようになります。([#95448](https://github.com/kubernetes/kubernetes/pull/95448), [@alculquicondor](https://github.com/alculquicondor)) [SIG Scheduling]
  - :pencil: これも[Default Pod Topology Spread を betaに昇格](#default-pod-topology-spread-to-beta)させる作業の一貫です。 kube-schedulerの設定方法は現在[Scheduler Configuration](https://kubernetes.io/docs/reference/scheduling/config/)と[Scheduling Policies](https://kubernetes.io/docs/reference/scheduling/policies/)(現在legacy扱い)を使う方法ありますが、後者で [`SelectorSreadPolicy`](https://kubernetes.io/docs/reference/scheduling/policies/#priorities)を設定した時の挙動の変更です。

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

- "validates that there is no conflict between pods with same hostPort but different hostIP and protocol" というConformance Testのテストケースで、テストに加えて各 `hostPort` への接続性の検証も行うようにしました。([#96627](https://github.com/kubernetes/kubernetes/pull/96627), [@aojea](https://github.com/aojea)) [SIG Scheduling and Testing]
  - :pencil: このPRで追加されたテスト時における`hostPort`への接続性確認ですが、[`hostNetwork: true`がサポートされていないWindows](https://kubernetes.io/docs/setup/production-environment/windows/intro-windows-in-kubernetes/#v1-pod)でも[テストが動くようになっていたようです](https://github.com/kubernetes/kubernetes/pull/96627#issuecomment-733815350)。もともとサポートのない機能をテストしようとしてテストが落ちしまっているだけですので動作に影響は無いと思います。ちなみにですが、[#97003](https://github.com/kubernetes/kubernetes/pull/97003)で修正が行われています。

# Bug or Regression （バグまたはリグレッション）
:pencil: backportされていないバージョンを利用している方はご注意ください⚠️

- [`LocalStorageCapacityIsolation`](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#local-ephemeral-storage) feature gateがdisabledな際にschedulerがそれを考慮しない問題を修正しました。([#96092](https://github.com/kubernetes/kubernetes/pull/96092), [@Huang-Wei](https://github.com/Huang-Wei)) [SIG Scheduling]
    - :pencil: [`LocalStorageCapacityIsolation`](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#local-ephemeral-storage) feature gateはデフォルトでenabledで、disabledにするケースは少ないと思われますが、disabledな場合、Podのephemeral volumeはschedulingにおいては無視されるべきなのですが、考慮してしまっていたというバグです。この修正は[v1.19.4](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.19.md#v1194), [v1.18.11](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.18.md#v11811)にもbackportされています。
- (legacy) scheduler policyを利用した場合に、`DefaultPreemption` Pluginがdisabledになってしまう問題を修正しました。([#96439](https://github.com/kubernetes/kubernetes/pull/96439), [@Huang-Wei](https://github.com/Huang-Wei)) [SIG Scheduling and Testing]
    - :pencil: [Scheduling Policies](https://kubernetes.io/docs/reference/scheduling/policies/)(現在legacy扱い)を使ってkube-schedulerを設定すると、Preemptionが全く無効になってしまうバグの修正です。この修正は[v1.19.5](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.19.md#v1195)にもbackportされています。
- Podよりも前にそのNodeが削除された時、scheduler内部のcache snapshotが不整合になってしまう問題を修正しました。([#95130](https://github.com/kubernetes/kubernetes/pull/95130), [@alculquicondor](https://github.com/alculquicondor)) [SIG Scheduling]
    - :pencil: この修正は[v1.19.3](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.19.md#v1193), [v1.18.10](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.18.md#v11810)にもbackportされています。


# Other (その他の修正)

- Scheduler metricsエンドポイントへのリクエストが認証できない場合のメッセージを修正しました。([#94035](https://github.com/kubernetes/kubernetes/pull/94035), [@zhouya0](https://github.com/zhouya0)) [SIG Scheduling]
  - :pencil: 内部実装でlegacyschemaを利用し続けたいたのが原因で、認証エラーの際に、認証エラーとは無関係のエラーがレスポンスされていたのですが、この修正で正しい認証エラーメッセージがレスポンスされるようになりました。
- kube-schedulerスタート時に処理されたcomponent configがログとして出力されるようになりました。([#96426](https://github.com/kubernetes/kubernetes/pull/96426), [@damemi](https://github.com/damemi)) [SIG Scheduling]
  - :pencil: 便利ですね！
- Scheduler framework interfaceが`pkg/scheduler/framework/v1alpha`から`pkg/scheduler/framework`に移動しました。 ([#95069](https://github.com/kubernetes/kubernetes/pull/95069), [@farah](https://github.com/farah)) [SIG Scheduling, Storage and Testing]

# :pencil: おまけ
[Scheduling Framework](https://kubernetes.io/docs/concepts/scheduling-eviction/scheduling-framework/)登場以降、かなり柔軟にカスタムスケジューラがkubernetesをforkせずに開発ができるようになってきており、[kubernetes-sigs/scheduler-plugins](https://github.com/kubernetes-sigs/scheduler-plugins)にいくつかPlugin拡張が公開されています。ぜひ見てみると良いと思います！


[^0]: Nodeの空き容量メトリクスも出してほしいですね。
[^1]: 正確には同一の `service, replication controller, replica set or stateful set`配下のPodに限られます
[^2]: 一般には複数のPluginが合成された関数になります
[^3]: kube-schedulerにおけるDefaultPreemption PluginはprofileのScore関数を考慮せず、[VictimのPDB違反数、最大優先度の値、優先度の和、といった指標でVictim Nodeを一つにしぼっています](https://github.com/kubernetes/kubernetes/blob/v1.20.0/pkg/scheduler/framework/plugins/defaultpreemption/default_preemption.go#L432-L443)、v1.19においては、default preemptionロジックのplugin化にフォーカスされたため、Score関数の公開は行われなかったという背景があります。ここからも分かる通り、default preemptionは、カスタムScore Pluginを利用して、できるだけPodを効果的にPackingしたいと言うような場合に不都合が発生する場合があります。