# KEP-407: Gang Scheduling(LeaderWorkerSet)
[kubernetes-sigs/lws](https://github.com/kubernetes-sigs/lws) の Kubernetes Enhancement Proposal(KEP-407)。[[LeaderWorkerSet]](LWS、Leader/Workerの非対称レプリカを扱う Kubernetes API、分散LLM推論・訓練を主用途とする)にギャングスケジューリング対応を追加する提案。2025-04-08 起草。sig-apps 傘下のリポジトリ内 KEP のため、著者は個別に列記されず、起点は [Issue #167](https://github.com/kubernetes-sigs/lws/issues/167) の報告者。(Source: README frontmatter、Issue #167)
## 動機:部分スケジューリングによるリソースデッドロック
ギャングスケジューリング対応がない状態では、クラスタ資源が逼迫しているとき、スケジューラが Leader Pod を優先してスケジュールし、対応する Worker Pod は pending のまま放置されうる。LWS が実装する分散推論サービスは Leader・Worker の全 Pod が揃って初めて機能するため、この部分スケジューリングは「クラスタ資源を消費しているのにどの推論サービスも提供できない」状態を生み、リソースデッドロックに陥る。ギャングスケジューリングは、レプリカ内の全 Pod が「揃ってスケジュールされる」か「まったくスケジュールされない」かのいずれかを保証することで、これを防ぐ。(Source: Motivation, Issue #167)
Goal は各カスタムスケジューラ(Volcano・coscheduling scheduler-plugin・YuniKorn等)向けに、LWS の各レプリカに対応する PodGroup リソースを作成できるようにすることに絞られ、具体的なギャングスケジューリングポリシー自体の実装は Non-Goal とされる。
## インターフェース設計:プラガブルな ReplicaResourceProvider
```go
type BaseResourceProvider interface {
CreateHeadlessService(ctx context.Context, lws *leaderworkerset.LeaderWorkerSet) error
CreateResourceClaim(ctx context.Context, lws *leaderworkerset.LeaderWorkerSet) error
}
type SchedulerProvider interface {
CreatePodGroupIfNotExists(ctx context.Context, lws *leaderworkerset.LeaderWorkerSet, leaderPod *corev1.Pod) error
InjectPodGroupMetadata(pod *corev1.Pod) error
}
type ReplicaResourceProvider interface {
BaseResourceProvider
SchedulerProvider
}
```
`SchedulerProvider` は PodGroup 管理を抽象化する新規インターフェースで、`CreatePodGroupIfNotExists` は Pod コントローラから呼ばれ PodGroup CRD を作成し、`InjectPodGroupMetadata` は Pod Webhook から呼ばれ Pod に PodGroup 所属先を設定する。所属先の設定方法はスケジューラごとに異なり(Volcano はアノテーション `scheduling.k8s.io/group-name`、coscheduling scheduler-plugin はラベル `scheduling.x-k8s.io/pod-group`)、この差異を `InjectPodGroupMetadata` の実装側に閉じ込める設計になっている。YuniKorn のように PodGroup CRD 自体を持たないスケジューラは `CreatePodGroupIfNotExists` を no-op(`nil` 返却)にすればよい。
`BaseResourceProvider` はヘッドレスサービス・ResourceClaim 作成という、LWS に固有で全カスタムスケジューラ共通の処理を切り出したもので、`defaultBaseResourceProvider` として1つの既定実装を提供し、各カスタムスケジューラ実装はこれを埋め込むか独自実装するかを選べる。この分割の狙いは、将来レプリカ次元の新規リソースを追加する際に `BaseResourceProvider` だけを変更すればよく、`SchedulerProvider`・`ReplicaResourceProvider` 自体への変更を避けられる点にある。Pod コントローラ・Pod Webhook の新規属性はいずれも `ReplicaResourceProvider` 型で持たれ、新しいカスタムスケジューラを追加する場合はこのインターフェースを実装するだけでよい。
## PodGroup のライフサイクルとシーケンス
PodGroup 名は `lws.Name-groupIndex` の命名規則(groupIndex は Pod と同一)を取り、Leader Pod の作成をトリガに以下の順で処理される。
1. sts コントローラ(kube-controller-manager)が Leader Pod を作成
2. Pod Webhook が Leader Pod の Label/Annotation に PodGroup 所属を書き込む(mutating)
3. Pod コントローラが Leader Pod の作成を検知し、PodGroup を作成、OwnerReference を Leader Pod に設定し、MinResources・MinAvailable を設定
4. Pod コントローラが Worker sts を作成
5. sts コントローラが Worker Pod を作成
6. Pod Webhook が Worker Pod にも同じ PodGroup 所属を設定(groupIndex は Pod コントローラが Worker sts 作成時点で既に設定済みのため直接取得できる)
PodGroup の OwnerReference を Leader Pod に設定することで、PodGroup のライフサイクルは Leader Pod と完全に同期する。LWS のスケールダウン・削除・ローリングアップデートによる Leader Pod の再作成いずれの場合も、PodGroup は自動的に削除・再作成される。エラーハンドリングは、Webhook 側(`InjectPodGroupMetadata`)はアノテーション/ラベル設定のみで通常エラーにならないが、エラーを返す実装であれば sts コントローラの標準的なバックオフ・リトライに委ねられ、Pod コントローラ側(`CreatePodGroupIfNotExists`)は controller-runtime のフォールバックリトライで throttling・API サーバ切断に対処する。
## StartupPolicy による MinMember の切り替え
LWS の既存概念である StartupPolicy に応じて PodGroup の `MinMember` 設定を切り替える。
- **LeaderCreated Policy(既定)**: `MinMember` はレプリカ全体のサイズ(1 Leader + (size-1) Worker)。レプリカ内の全 Pod が揃わない限りスケジューリングをブロックする。
- **LeaderReady Policy**: `MinMember` は 1。Leader Pod 単独で即座にスケジュール可能となり、ギャングスケジューラによってブロックされない。
いずれのポリシーでも `MinResources` は常にレプリカ全体(1 Leader + (size-1) Worker)分を要求する。クラスタ資源が不足している状況で Leader Pod だけをスケジュールしても、その後 Worker Pod がリソース不足で作成に失敗するだけで無意味なため、リソース見積もりだけはポリシーに関わらずレプリカ全体分を維持する設計である。
## リスクと緩和策
- **保守コストの増大**: カスタムスケジューラとの統合が増えるほど LWS コアの保守負担が増す。緩和策として、LWS バージョンとサポートするスケジューラバージョン・PodGroup API依存関係の互換性マトリクスを文書化し、各スケジューラチーム自身が自分の統合コード・ドキュメント・バージョン互換性を保守する(LWS コアチームへの集中を避ける)方針を採る。
- **StartupPolicy とスケジューラ機能差の不整合**: PodGroup実装が `MinMember` と `MinResources` の同時設定をサポートしない場合、LeaderReady Policy 下で Leader Pod はスケジュールに成功したのに Worker Pod がリソース不足で作成失敗する、というシナリオが起こりうる(スケジューラがレプリカ全体の必要資源を正しく評価できないため)。この限界はドキュメントで明示する対応に留める。
## 検討され却下された代替案
PodGroup の作成主体を Pod コントローラではなく LWS コントローラに置く案も検討された。この場合 LWS の作成を検知した LWS コントローラがレプリカ数分の PodGroup をまとめて作成し、OwnerReference を LWS に設定する。しかしこの方式は、スケールアップ/ダウン時に対応する PodGroup の作成・削除処理が別途必要になり、ローリングアップデート時に `maxSurge` が設定されていれば既存 PodGroup の更新に加え追加の PodGroup 作成も必要になるなど複雑さが増すため、不採用となった。採用された Pod コントローラ主導・Leader Pod への OwnerReference 方式の方が、既存の Pod ライフサイクル管理にギャングスケジューリングの寿命を素直に委譲できる点で単純である。
## 出典
- kubernetes-sigs/lws contributors, "KEP-407: Gang Scheduling", `keps/407-gang-scheduling/README.md`, KEP drafted 2025-04-08, 参照日 2026-08-19。
- [Issue #167](https://github.com/kubernetes-sigs/lws/issues/167)(動機となった部分スケジューリング問題の報告、本文中で参照)。