Kubernetes 1.25がリリースされましたね ![]()
今回もKubernetes v1.25のCHANGELOGをベースにSIG Schedulingに関する機能について紹介していきます。
過去の変更内容:
- Kubernetes 1.24: SIG Scheduling の変更内容
- Kubernetes 1.23: SIG Scheduling の変更内容
- Kubernetes 1.22: SIG Scheduling の変更内容
1.25変更点の所感
- v1.24に引き続きPod Topology Spread関連の機能追加が目玉となっています。
NodeInclusionPolicyEnableMatchLabelKeysInPodTopologySpread
- kube-schedulerのComponentConfigがGAし
kubescheduler.config.k8s.io/v1が利用可能になりました。 - それ以外は軽微なものばかりです。
下記
がついた文章は、CHANGELOGの公式内容ではなく筆者の補足です。
What's new! (新情報)
ありません
Urgent Upgrade Notes(必ず一読してからアップグレードしなければならない事項)
ありません
Deprecation(非推奨)
ありません
API Changes(API変更)
- Add
NodeInclusionPolicytoTopologySpreadConstraintsin PodSpec. (#108492, @kerthcet)-
KEP-3094: take toleration/taints into considering when computing skew
-
feature gate: NodeInclusionPolicyInPodTopologySpread(v1.25ではalpha) -
Pod Topology Spreadの超最前線 MinDomains、NodeInclusionPoliciesについてが詳しく解説しています -
PodSpec.TopologySpreadConstraint.{NodeAffinityPolicy|NodeTaintsPolicy}={Ignore|Honor}が設定できるようになります-
デフォルトがそれぞれ違うので注意です。それぞれのデフォルト値は NodeAffinityPolicy=Honor,NodeTaintsPolicy=Ignoreです。公式ドキュメントでは、nodeSelector/nodeAffinityはrespectするという表記がありますが、tolerationについては記載がなく、これまでrespectされていなかったためこの挙動になっていると思われます。
-
-
NodeAffinityPolicy=Ignore, Honorの挙動の違い
おさらい
spec:
topologySpreadConstraints:
# 複数指定したらAND-ed
- topologyKey: zone # zone単位で散らしたい(node label keyを指定できる. domainと呼びます)
maxSkew: 1 # 各zoneに居るlabelSelectorにマッチする
labelSelector: # このselectorにマッチするpod数の偏りは1以内にしたい
matchLabels:
foo: bar
whenUnsatisfiable: DoNotSchedule # maxSkewを満たせない場合はscheduleしない
# 'ScheduleAnyway'だと無視してスケジュールする
# 今回追加されたのは下2つ
nodeAffinityPolicy: Ignore|Honor # skewを計算する対象のnodeにpodのnode affinity/selectorを考慮するかどうか(default=Honor)
nodeTaintsPolicy: Ignore|Honor # skewを計算する時に対象のnodeにpodのtoleraitonを考慮するかどうか(default=Ignore)
シナリオ
4ノードが2つのゾーンに存在していて、zone1に2 pod, zone2に3 pod稼働しているとします。(label selectorは話を簡単にするために、全部マッチするとします。)。ここに、zoneに対するpod topology spreadと worker3に対するanti node-affinity(worker3にはスケジュールされない) をもったtest-podが作成されたとします。
| zone | zone1 | zone2 | ||
|---|---|---|---|---|
| node | worker | worker2 | worker3 | worker4 |
| existingPods | pod1 | pod2 | pod3, pod4 | pod5 |
| vacancy | 空き無し | 空き無し | 空き有り | 空き有り |
test-podのaffinity
|
○ | ○ | ✗ | ○ |
NodeAffinityPolicy=Honor(default)の挙動
各nodeの対象pod数の計算の際、Podに指定されたnode-affinityにマッチするnodeだけが対象になります。すると、下記のようになるため、domain間のskewは 2(zone1)-1(zone2)=1 となり、zone2にtest-podをscheduleすれば、skewが下がるため、zone2にscheduleされようとします。test-podはworker3へanti node-affinityを持っているため、結果としてworker4にスケジュールされます。
| zone | zone1 | zone2 | ||
|---|---|---|---|---|
| node | worker | worker2 | worker3 | worker4 |
| existingPods | pod1 | pod2 | pod3, pod4 | pod5 |
| vacancy | 空き無し | 空き無し | 空き有り | 空き有り |
test-podのaffinity
|
○ | ○ | ✗ | ○ |
| skew計算対象Pod数 | 1 | 1 | 対象外 | 1 |
| zone毎Pod数 | 2 | 1 | ||
| TopologySpreadの zone選択 |
✗ | ○ | ||
test-podの最終的なschedule先 |
✗ | ✗ | ✗ | ○ |
NodeAffinityPolicy=Ignoreの挙動
各nodeの対象pod数の計算は下記のようになるため、domain間のskewは 3(zone2)-2(zone1)=1 となり、zone1にtest-podをscheduleすれば、skewが下がるため、zone1にscheduleされようとしますが、zone1には空いているノードが存在しないため、test-podはPendingになります。
| zone | zone1 | zone2 | ||
|---|---|---|---|---|
| node | worker | worker2 | worker3 | worker4 |
| existingPods | pod1 | pod2 | pod3, pod4 | pod5 |
| vacancy | 空き無し | 空き無し | 空き有り | 空き有り |
test-podのaffinity
|
○ | ○ | ✗ | ○ |
| skew計算対象Pod数 | 1 | 1 | 2 | 1 |
| zone毎Pod数 | 2 | 3 | ||
| TopologySpreadの zone選択 |
○ | ✗ | ||
test-podの最終的なschedule先 |
なし | |||
- v1.25はGolang 1.19を使うようになります。このPRではGAがまだ利用できないため1.19rc2を使っています。(#111254, @dims)
- Pod障害Policyに応じてPod障害を処理するようになりました (#111113, @mimowo)
-
DisruptionTargetPod Condition Typeが導入されます.reasonフィールドはpod停止の理由を示します:-
PreemptionByKubeScheduler: kube-schedulerによるPodのpreempt -
DeletionByTaintManager:NoExecutetaintに伴うtaint managerによるPodのdelete -
EvictionByEvictionAPI: Eviction APIによるPodのevict -
DeletionByPodGC: PodGCによるorphaned Podの削除 - (#110959, @mimowo)
-
KEP-3329: Retriable and non-retriable Pod failures for Jobs
-
feature gate: PodDisruptionConditions(v1.25ではalpha) -
JobのPodが失敗した際に、このDisruptionTargettypeのConditionを使ってpodが削除された際の失敗処理が定義できます
-
- kube-schedulerのComponentConfigがGAし、
kubescheduler.config.k8s.io/v1が利用可能です。v1ではSelectorSpreadPluginは削除されています。(#110534, @kerthcet)-
v1.24でデフォルトでoffになっているPluginで、今後はPodToplogySpreadを使うことが推奨されています。
-
- Local Storage Capacity Isolationが1.25でGAになります。 root file systemをチェックできないシステム(rootless)では、 kubeletの
--local-storage-capacity-isolation=falseを使って無効化してください。無効化されるとpodでlocal ephemeral storage request/limitやemptyDir sizeLimitが利用できなくなります. (#111513, @jingxu97) -
NodeResourcesFitpluginのエラーメッセージにおいて、許可されているScoringStrategyTypeを表示するようになりました。(#111206, @SataQiu)-
plugin初期化時(kube-scheduler起動時)のエラーメッセージの改善です。 -
E0718 07:13:34.754796 9974 run.go:74] "command failed" err="initializing profiles: creating profile for scheduler name default-scheduler: initializing plugin \"NodeResourcesFit\": scoring strategy XXXX is not supported, only [LeastAllocated MostAllocated RequestedToCapacityRatio] is accepted"と出るようになります
-
- logging設定向けのGo APIが
k8s.io/component-baseからk8s.io/component-base/logs/api/v1に移動しました。 設定ファイルのフォーマットはコマンドラインフラグはこれまでと同じです。(#105797, @pohly) -
PodTopologySpreadがrolling upgrade時に尊重されるようになります。 (#111441, @denkensk)-
KEP-3243: respect pod topology spread after rolling upgrades
-
feature gate: EnableMatchLabelKeysInPodTopologySpread(v1.25ではalpha) -
解決したい現象
- Deploymentをsurgeありでrolling updateすると、Topology SpreadがmaxSkewを越えてしまうことがありました。
- 先に新しいReplicaSet Podが作成され、後から旧ReplicaSet Podが削除されますが、Pod Topology Spreadはscheduling時にしか有効じゃないので、古いReplicaSet Podが消されるときにmaxSkewを超えてしまう場合がありました。
- ただ、通常Deployment配下のPodの
PodSpec.ToplogySpread.LabelSelectorは新旧ReplicaSetを跨って同じになるので、ReplicaSet Pod毎にskewを計算するのは今のSpecだとできませんでした。
-
解決法
-
KEP-3243: respect pod topology spread after rolling upgradesで、「skewを計算するPodの集合」を定義する、
PodSpec.TopologySpreadConstraint.MatchLabelKeysというAPIが導入されました。このフィールドに定義されているlabelの値が等しいものをskew計算のグループとして捉えるようになります。 - 通常Deploymentで使う場合は
matchLabelKeys: ["pod-template-hash"]で良いです。 - こうするとReplicaSetそれぞれでskewが計算され、古いreplicasetは関係なくなります。
-
KEP-3243: respect pod topology spread after rolling upgradesで、「skewを計算するPodの集合」を定義する、
-
FEATURE(機能追加)
- Feature gate
CSIMigrationがenabledに固定され、CSIMigrationはGAになりました。このfeature gateはv1.27で削除予定です. (#110410, @Jiawei0227) -
CSIMigrationAWSがGAに昇格し、trueに固定されました。 (#111479, @wongma7) -
CSIMigrationGCEがGAに昇格し、trueに固定されました。(#111301, @mattcary)
バグ修正
- Preemption(PostFilter)中にPluginメトリクスが記録されなかったバグを修正しました。 (#108727, @sanposhiho)
-
過去バージョンへはbackportされていません。
-
- Jobコントローラで
activeDeadlineSecondsの設定が有効にならないバグを修正しました。 (#110294, @harshanarayana)-
JobReadyPodsfeature gateが有効(v1.24以降でデフォルトで有効)な場合にactiveDeadlineSecondsを超えてもJob Podが削除されずに残るバグがありました。 -
v1.22以降すべてのバージョンにbackportされています。
-
- CSI migrationでinline volumesがattach limitとしてカウントされないバグを修正しました。(#107787, @Jiawei0227)
-
CSI driverはNodeGetInfoResponseを使ってmax_volumes_per_nodeを定義できます(参照:Volume Limits - Kubernetes CSI Developer Documentation) -
しかし、CSI Migrationされたpod spec内のvolumeがvolume limitsにカウントされていませんでした。
-
- scheduler plugin開発者向けの変更: Scheduler Frameworkが提供するShared PodInformerが空のIndexerで初期化されるようになりました。これによってpluginはカスタムIndexerを追加できるようになります。 Indexerの追加はコンフリクトしない限りにおいて追加可能です。(#110663, @fromanirh)
-
これまではIndexerがnilだったので、Indexerを使いたいためだけに、カスタムScheduling Pluginで自分でInformerを初期化していたのでとても便利になります。 -
ただし、schedulerのShared Informerはnon-terminal podのみが対象なので注意してください。
-