Open13

kubernetes-sigs/kueue

bells17bells17

cores/ClusterQueueReconciler

対象リソース: ClusterQueue

イベント受信元リソース

  • ClusterQueue
  • Workload

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/controller/core/clusterqueue_controller.go#L194-L204

イベント受信時には

  • キャッシュ更新処理
  • Queue ManagerへのClusterQueueの更新処理

を行っている

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/controller/core/clusterqueue_controller.go#L99-L149

Reconcile処理ではStatus更新処理を行っている

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/controller/core/clusterqueue_controller.go#L67-L90

bells17bells17

core/QueueReconciler

対象リソース: Queue

イベント受信元リソース

  • Queue
  • Workload

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/controller/core/queue_controller.go#L165-L172

イベント受信時には

  • キャッシュ更新処理
  • Queue ManagerへのClusterQueueの更新処理

を行っている

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/controller/core/queue_controller.go#L91-L134

Reconcile処理ではStatus更新処理を行っている

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/controller/core/queue_controller.go#L64-L89

bells17bells17

core/WorkloadReconciler

対象リソース: Workload

イベント受信元リソース

  • Workload

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/controller/core/workload_controller.go#L229-L235

イベント受信時には

  • Workloadリソースイベントをwatcherに通知
  • Queue ManagerへのWorkload情報のアップデート
  • キャッシュの更新
  • TODO: その他(r.queues.QueueAssociatedInadmissibleWorkloads(wl)など)
    • → BestEffortFIFOをqueue戦略として使ってる場合、nominateに失敗したworkloadを一時除外しているので、workloadがfinishedで成功したので、nominateに失敗したworkloadの再nominateは成功するんじゃね?ということで再度queueingしてるのではないかと

を行っている

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/controller/core/workload_controller.go#L97-L221

Reconcile処理では紐づく

  • Queue
  • ClusterQueue

を調べ、Queue ManagerにQueue/ClusterQueueが無ければ、Workload conditionの"Admitted' conditionをfalseに設定する

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/controller/core/workload_controller.go#L71-L95

bells17bells17

JobReconciler

対象リソース: Job

イベント受信元リソース

  • Job

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/controller/workload/job/job_controller.go#L91-L116

Reconcile

queue設定が無ければ処理しない

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/controller/workload/job/job_controller.go#L136-L139

対象jobにownerReferenceが紐付けられているworkload一覧を取得

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/controller/workload/job/job_controller.go#L143-L148

ensureAtMostOneWorkload

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/controller/workload/job/job_controller.go#L150-L155

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/controller/workload/job/job_controller.go#L339-L400

workloadが無い場合は作成する

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/controller/workload/job/job_controller.go#L158-L169

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/controller/workload/job/job_controller.go#L316-L337

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/controller/workload/job/job_controller.go#L402-L434

jobが既に終了している場合は、終了のステータス(成功 or 失敗)をworkloadのconditionに記録して処理終了

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/controller/workload/job/job_controller.go#L171-L183

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/controller/workload/job/job_controller.go#L436-L460

jobがsuspend状態の場合、wl.Spec.Admissionが既に設定されていればjobを開始し(suspendをfalseにする)処理を終了し、そうでなければjobのアノテーションから取得したqueue名の更新処理を行い処理を終了する

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/controller/workload/job/job_controller.go#L185-L210

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/controller/workload/job/job_controller.go#L259-L290

jobがsuspend状態ではない場合、wl.Spec.Admissionが未設定であればjobを停止する(suspend=trueにする)

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/controller/workload/job/job_controller.go#L212-L220

要約

  • jobのsuspend管理を行いjobを起動するのはこいつ
  • jobに紐づくworkloadの作成を行う
  • workloadの重複管理を行い、重複があれば削除を行う(reconcilerが同時に動いたケースなど?)
  • wl.Spec.Admissionの設定は別のやつが行う
bells17bells17

scheduler.Start

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/main.go#L138-L142

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/scheduler/scheduler.go#L68-L72

queueからworkloadを取得

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/scheduler/scheduler.go#L81-L87

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/queue/manager.go#L400-L419

workloadが空だと

                 default:
			m.cond.Wait()
		}

のように sync.Cond.Wait() により sync.Cond.Broadcast() の実行まで待機する
つまりschedulerはReconcilerのようにリソースウォッチの代わりに sync.Cond によって処理対象データが来るのを待機する仕組みになっている

snapshotを生成

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/scheduler/scheduler.go#L89-L90

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/cache/snapshot.go#L29-L54

Cluster Autoscalerのスケジューリングのシュミレーションのようなことをするためのチェック?

snapshotのデータからシュミレーションをやるためには

  • ClusterQueues
  • ResourceFlavors

が必要で、あとcacheの持つcohort情報の更新が必要というのがなんとなく予想できる

nominate

渡されたworkloadsからTODOしてフィルタしたentriesを返す

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/scheduler/scheduler.go#L92-L94

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/scheduler/scheduler.go#L165-L189

assignFlavors

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/scheduler/scheduler.go#L191-L232

e.TotalRequestsに対して以下の処理を行う
その前にe.TotalRequestsの説明

e.TotalRequestsの生成箇所

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/workload/workload.go#L58-L86

  1. TODO: ここはすでにadmit済であればadmitしたflavorを取り出してるけどまだflavorが入るところは読んでないのでわからない: https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/workload/workload.go#L63-L69
  2. for _, ps := range spec.PodSets { でspec.PodSetsをループしてるけどspec.PodSetsは1つじゃないとstartJobされないので1つ以外のケースは基本的に無いはず: https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/workload/workload.go#L70
  3. PodSetResourceを生成してる: https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/workload/workload.go#L71-L83
assignFlavorsの続き
  1. というわけでpodSetは1つしかないはずなので for i, podSet := range e.TotalRequests { は1ループしかしないはず: https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/scheduler/scheduler.go#L200
  2. podSetの各リソース要求に対してflavoredRequestsを生成するために以下の処理を実行: https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/scheduler/scheduler.go#L202-L220
  1. 生成したflavoredRequestsをe.TotalRequestsにセット: https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/scheduler/scheduler.go#L227
  2. 借用リソースがあればe.borrowsにセット : https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/scheduler/scheduler.go#L228-L230
  3. assign成功であればtrueを返す: https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/scheduler/scheduler.go#L231
findFlavorForResource

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/scheduler/scheduler.go#L278-L318

  1. flavorSelectorでClusterQueue.LabelKeys[name]に指定したキー以外のlabelをpod specのNodeSelectorとaffinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTermsから取り除いたnodeaffinity.RequiredNodeAffinityを生成: https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/scheduler/scheduler.go#L290 https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/scheduler/scheduler.go#L320-L364
  2. cq.RequestableResources[name]に対して以下のループ処理(nameはcpuなどのリソース種別が入る): https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/scheduler/scheduler.go#L291-L316
  1. fitするflavorがなければその結果を返す: https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/scheduler/scheduler.go#L317
fitsFlavorLimits

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/scheduler/scheduler.go#L366-L390

  1. flavorの現在の使用量(used)とこれから利用したい量の総量をflavor.Maxが超えれば即fitせずとしてreturn : https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/scheduler/scheduler.go#L370-L373
  2. ClusterQueueに紐づくcohortがある場合、cohort単位のused/totalにデータを差し替え: https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/scheduler/scheduler.go#L374-L379
  3. 借受分が無ければborrowを0にする : https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/scheduler/scheduler.go#L380-L383
  4. 借受分をあわせても合計値を上回ってしまう場合はfitせずとしてreturn: https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/scheduler/scheduler.go#L384-L388
  5. fitした場合はborrowと合わせてtrueを返す: https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/scheduler/scheduler.go#L389

CohortのUsedResources/RequestableResourcesはSnapshot生成時の↓のあたりでやってる
(要はどうメインのcohortを持つClusterQueueの各flavoのflavor.Minを足し合わせた値をRequestableResourcesとして設定して、現在の使用値の合計をUsedResourcesとして設定してる)

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/cache/snapshot.go#L44-L52

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/cache/snapshot.go#L81-L108

このcohortの概念だけど、ResourceFlavorがあることで便利かもしれないけど始めの理解をややこしくしてる気がする

sort

ソートはコメントまんまだと思う

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/scheduler/scheduler.go#L96-L97

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/scheduler/scheduler.go#L402-L416

注文基準は少なくなります。
1.借りる前に最小割り当ての下で要求します。
2.作成タイムスタンプのFIFO。

admit

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/scheduler/scheduler.go#L99-L127

各entiryごとにadmit処理

  1. nominated statusじゃないのはskip: https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/scheduler/scheduler.go#L107-L109
  2. 借受(borrow)があるもので、既に同名のcohortがadminされている場合はskipステータスにする(cohortの借受上限を超える可能性があるから?1つだけをadminするなら上限を超えることは無いため安全のためにそうしてる感じ?) : https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/scheduler/scheduler.go#L111-L115
  3. admit処理 : https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/scheduler/scheduler.go#L116-L121

admit処理

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/scheduler/scheduler.go#L234-L276

  1. admissionを生成してWorkload.Spec.Admissionに設定 : https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/scheduler/scheduler.go#L239-L250
  2. s.cache.AssumeWorkloadでClusterQueueにWorkloadを保存し、ClusterQueueの使用値の情報なども更新する: https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/scheduler/scheduler.go#L251-L254
  3. admissionを組み込んだworkloadを保存する(失敗時はClusterQueueを元に戻したり、requeueしたりといった復元処理を行う) : https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/scheduler/scheduler.go#L256-L273

requeue

最後にassumedじゃないentryをrequeueする

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/scheduler/scheduler.go#L129-L140

bells17bells17

ClusterQueue戦略の補足

↓の補足
https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/docs/concepts/cluster_queue.md#queueing-strategy

StrictFIFO

多分デフォルト的な立ち位置のQueue戦略
書いてある通り .metadata.creationTimestamp によりqueueがソートされる

BestEffortFIFO

StrictFIFOに加え↓のnominate処理で

  • Label/Taint条件がマッチしない
  • Fitするflavorが存在しない

といったworkloadがある場合は一時的に除外し、他のworkloadのadmitを優先するという戦略

個人的には基本こっちなのでは?という気がするんだけど、そうするとケースによっては小さめのworkloadがずっと割り当たって大きめのworkloadの処理が始まらない的な問題が発生したりする??

https://github.com/kubernetes-sigs/kueue/blob/v0.1.0/pkg/scheduler/scheduler.go#L165-L189

bells17bells17

cacheパッケージについて

https://github.com/kubernetes-sigs/kueue/tree/v0.1.0/pkg/cache

始めはなんでわざわざキャッシュデータを用意するんだろうと思ったけど主に以下の理由??

  • Snapshotを生成するため
  • clusterQueuesデータ生成のため(内部的な処理を行うデータはこのcacheパッケージのclusterQueuesが保持してる)
  • cohortsデータ生成のため(内部的な処理を行うデータはこのcacheパッケージのcohortsが保持してる←というよりcohortはAPIデータとしてはcohort名しか保持していない)
  • assumedWorkloadsを利用したClusterQueueデータのworkloadデータ管理のため
  • resourceFlavorsについてはまんまResourceFlavorリソースのデータだと思うので、わざわざキャッシュすべき理由がよくわからない