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関連の機能追加が目玉となっています。
NodeInclusionPolicy
EnableMatchLabelKeysInPodTopologySpread
- kube-schedulerのComponentConfigがGAし
kubescheduler.config.k8s.io/v1
が利用可能になりました。 - それ以外は軽微なものばかりです。
下記 がついた文章は、CHANGELOGの公式内容ではなく筆者の補足です。
What's new! (新情報)
ありません
Urgent Upgrade Notes(必ず一読してからアップグレードしなければならない事項)
ありません
Deprecation(非推奨)
ありません
API Changes(API変更)
- Add
NodeInclusionPolicy
toTopologySpreadConstraints
in 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)
-
DisruptionTarget
Pod Condition Typeが導入されます.reason
フィールドはpod停止の理由を示します:-
PreemptionByKubeScheduler
: kube-schedulerによるPodのpreempt -
DeletionByTaintManager
:NoExecute
taintに伴う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が失敗した際に、この
DisruptionTarget
typeのConditionを使ってpodが削除された際の失敗処理が定義できます
-
- kube-schedulerのComponentConfigがGAし、
kubescheduler.config.k8s.io/v1
が利用可能です。v1
ではSelectorSpread
Pluginは削除されています。(#110534, @kerthcet)-
v1.24でデフォルトでoffになっているPluginで、今後は
PodToplogySpread
を使うことが推奨されています。
-
v1.24でデフォルトでoffになっているPluginで、今後は
- 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) -
NodeResourcesFit
pluginのエラーメッセージにおいて、許可されている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)-
JobReadyPods
feature 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にカウントされていませんでした。
-
CSI driverは
- scheduler plugin開発者向けの変更: Scheduler Frameworkが提供するShared PodInformerが空のIndexerで初期化されるようになりました。これによってpluginはカスタムIndexerを追加できるようになります。 Indexerの追加はコンフリクトしない限りにおいて追加可能です。(#110663, @fromanirh)
-
これまではIndexerが
nil
だったので、Indexerを使いたいためだけに、カスタムScheduling Pluginで自分でInformerを初期化していたのでとても便利になります。 - ただし、schedulerのShared Informerはnon-terminal podのみが対象なので注意してください。
-
これまではIndexerが