Skip to content

[KEP] Update KEP of the flavor fungibility feature#6133

Merged
k8s-ci-robot merged 9 commits into
kubernetes-sigs:mainfrom
pajakd:kep_fungibility
Jul 24, 2025
Merged

[KEP] Update KEP of the flavor fungibility feature#6133
k8s-ci-robot merged 9 commits into
kubernetes-sigs:mainfrom
pajakd:kep_fungibility

Conversation

@pajakd
Copy link
Copy Markdown
Contributor

@pajakd pajakd commented Jul 22, 2025

What type of PR is this?

/kind documentation

What this PR does / why we need it:

Which issue(s) this PR fixes:

Part of #5424

Special notes for your reviewer:

Does this PR introduce a user-facing change?

NONE

@k8s-ci-robot
Copy link
Copy Markdown
Contributor

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@k8s-ci-robot k8s-ci-robot added do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. kind/documentation Categorizes issue or PR as related to documentation. do-not-merge/release-note-label-needed Indicates that a PR should not merge because it's missing one of the release note labels. labels Jul 22, 2025
@k8s-ci-robot k8s-ci-robot added the cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. label Jul 22, 2025
@netlify
Copy link
Copy Markdown

netlify Bot commented Jul 22, 2025

Deploy Preview for kubernetes-sigs-kueue canceled.

Name Link
🔨 Latest commit 0f2d41d
🔍 Latest deploy log https://app.netlify.com/projects/kubernetes-sigs-kueue/deploys/68822ee39d20050008c4bae5

@k8s-ci-robot k8s-ci-robot added size/M Denotes a PR that changes 30-99 lines, ignoring generated files. release-note-none Denotes a PR that doesn't merit a release note. and removed do-not-merge/release-note-label-needed Indicates that a PR should not merge because it's missing one of the release note labels. labels Jul 22, 2025
Copy link
Copy Markdown
Member

@tenzen-y tenzen-y left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First questions.

After we try to schedule a podset in a resource flavor, we decide whether to traverse to the next flavor base on the `flavorFungibility`. If the assignment mode is `NoFit`, we will always try the next flavor until the last one. When the assignment mode is `Preempt`, we can return the current assignment if `WhenCanPreempt` is `Preempt`. Otherwise if the assignment mode is `Fit`, we try the next flavor only when we need borrowing in the current flavor and `WhenCanBorrow` is `TryNextFlavor`.
- (`Fit`, `NoBorrow`) is the most prefered
- (`Fit`, `Borrow`) is prefered over (`Preempt`, `NoBorrow`) if `WhenCanPreemptAndBorrow = AvoidPreemption`
- (`Preempt`, `NoBorrow`) is prefered over (`Fit`, `Borrow`) if `WhenCanPreemptAndBorrow = AvoidBorrowing`
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Preempt, NoBorrow) is prefered over (Fit, Borrow) if WhenCanPreemptAndBorrow = AvoidBorrowing

What does this mean? Does the whenCanPreemptAndBorrow: AvoidBorrowing respect Preempt and NoBorrow over the Fit? Or does this strategy avoid only Fit with borrow?

IIUC, Fit contains 2 patterns: (1 the workload fits nominalQuota (2 the workload fits borrowed quotas.

Copy link
Copy Markdown
Contributor Author

@pajakd pajakd Jul 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, so in my notation we have 4 interesting cases (Fit, NoBorrow), (Fit, Borrow), (Preempt, NoBorrow), (Preempt, Borrow).

  1. WhenCanPreemptAndBorrow = PreferBorrowing (current) the order is (Fit, NoBorrow), (Fit, Borrow), (Preempt, NoBorrow), (Preempt, Borrow)
  2. WhenCanPreemptAndBorrow = PreferPreemption (new) the order is (Fit, NoBorrow), (Preempt, NoBorrow), (Fit, Borrow), (Preempt, Borrow)

TryNextFlavor FlavorFungibilityPolicy = "TryNextFlavor"
)

type FlavorSelectionStrategy string
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have any reason to choose strategy suffix?
Could we select FlavorSelectionPolicy to align with FlavorFungibilityPolicy?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, of course. Changed to FlavorSelectionStrategy

Comment on lines +176 to +177
AvoidPreemption FlavorSelectionStrategy = "AvoidPreemption"
AvoidBorrowing FlavorSelectionStrategy = "AvoidBorrowing"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As also asked in the PR impl: #6132 (comment), I'm not convinced to the naming, the "Avoid" seems stronger than prefer. So, it is likely users would interpret like "do nothing" when all flavors are (Preempt, NoBorrow).

So I would be leaning to "PreferPreemption", "PreferBorrowing", or an enum field "preference: Preemption/Borrowing", wdyt?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also think that new strategies should not be "Avoid" since it would be better to mention what will happen rather than what will NOT happen.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. So I guess more people prefer prefer :) Updated.

Comment thread keps/582-preempt-based-on-flavor-order/README.md Outdated
Comment thread keps/582-preempt-based-on-flavor-order/README.md Outdated
Comment thread keps/582-preempt-based-on-flavor-order/README.md Outdated
// other workloads.
// - `PreferPreemption`: prefer to allocate in a flavor that uses only the nominal quota
// even if it means preempting other workloads.
// +kubebuilder:validation:Enum={PreferBorrowing,PreferPreemption}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just Borrow,Preempt? Since the field is already whenCanPreemptAndBorrow it is already clear we have the two options.

// even if it means preempting other workloads.
// +kubebuilder:validation:Enum={PreferBorrowing,PreferPreemption}
// +kubebuilder:default="PreferBorrowing"
WhenCanPreemptAndBorrow FlavorSelectionPolicy `json:"preferredStrategy,omitempty"`
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I find this API still confusing a lot. Its form is similar to whenCanPreempt and whenCanBorrow, but the semantics is very differenent. whenCanPreempt and whenCanBorrow indicate actually: stop looking for new flavors. They mean when flavor which preempt -> do something, when flavor which can borrow -> do something.

The naming convention suggests the new field has the same nature, when a flavor which can preempt and borrow is encountered -> do something.

However, the nature of the field is very different, it means "once the set of flavors is determined, choose the one fitting the preference: Borrow or Preempt".

cc @tenzen-y @pajakd

Let me propose something.

Copy link
Copy Markdown
Contributor

@mimowo mimowo Jul 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The API I'm thinking towards is

flavorFungability:
  whenCanBorrow: Stop / TryNextFlavor
  whenCanPreempt: Stop / TryNextFlavor
  preferenceOrder: ["Preempt",  "PreemptWhileBorrowing", "Borrow"]

Now, the field is preferenceOrder because some users may want to position "PreemptWhileBorrowing" differently. So, by saying just "Preempt / Borrow" we are too constraining for the future.

I think what happens here is some implicit ordering currently "Borrow", "Preempt", "PreemptWhileBorrowing".

As mentioned in https://github.com/kubernetes-sigs/kueue/pull/6133/files#r2225166242 the story is really for a user which is using FairSharing, and we got feedback due to the very nature of fair sharing they want "Preempt", "PreemptWhileBorrowing", "Borrow".

However, I can imagine some users will want ["Preempt", "PreemptWhileBorrowing", "Borrow"] (say outside of FairSharing), so long term something like preferenceOrder might be helpful.

So, I propose to do not introduce new API for 0.13, just a beta level feature gate (for now), FairSharingWithFlavorFungabilityPrefersPreemption. I think this is a sensible default when FairSharing is used for the reasons explained in the Story. The feature gate will give us bailout option if some users are unhappy with the change (I think this is unlikely), yet will give us time to think of better API. I'm also ok to make the feature gate alpha for now.

Copy link
Copy Markdown
Contributor

@mimowo mimowo Jul 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, let me expand on the dependency on FairSharing as it was, rightfully, questioned when discussing with @pajakd @gabesaba .

What we want with this feature is to avoid borrowing when reclaim is enabled. Because if a workload borrows it is likely a preemption target of the workloads in CQs which are entitles to reclaim.

Initially I thought, and was mistaken, that FairSharing enables all CQs in the system to reclaim (which is the common configuration), but in fact a CQ may still disabled preemption.reclaimWithinCohort.

Let me rework the feature gate idea then. I think what makes sense it still to use implicit defaults until we have a better idea of what is needed.

So my proposal is:

  1. whenCanBorrow: Borrow & whenCanPreempt: TryNextFlavor -> implicit default to for preference to Borrow
  2. whenCanBorrow: TryNextFlavor & whenCanPreempt: Preempt -> implicit default to for preference to Preempt
  3. whenCanBorrow: Borrow & whenCanPreempt: Preempt -> implicit default does not matter because we just choose first
  4. whenCanBorrow: TryNextFlavor & whenCanPreempt: TryNextFlavor -> make implicit default depending on the enablement of FairSharing. This is enough to capture the idea of FairSharing to mix borrowing with reclaim, yet will only be scoped to CQs which have whenCanBorrow: TryNextFlavor & whenCanPreempt: TryNextFlavor.

EDIT: The intention for tying the default to FairSharing (in 4.) is the guesstimate of user preferences for "Preempt". The reason is that FairSharing with reclamation disabled is rather corner case usage, so I think it is reasonable to assume users who use FairSharing will prefer "Preempt" over "Borrowing".

All of this I would hide behind feature gate FlavorFungabilityImplicitPreferenceDefault.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once we hear from users no complains for a couple of releases (most likely scenario) we can just graduate FlavorFungabilityImplicitPreferenceDefault. If some users report issues we can think of preferenceOrder idea to override the implicit default. However, for now I think we can improve the default behavior using feature gate without expanding the API.

Copy link
Copy Markdown
Member

@tenzen-y tenzen-y Jul 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that we should graduate FlavorFungabilityImplicitPreferenceDefault FG to default enablement ones (beta, ga) since IIRC, pattern 2 (whenCanBorrow: TryNextFlavor & whenCanPreempt: Preempt) breaks the current behavior.

If we want to ship this behavior as a default, we should extend the API.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To base the discussion on the k8s guidelines, I think this would be it: Deprecating a feature or behavior.

In our case we are not deprecating the feature, but "behavior". I think the relevant rule would be "Rule #7: Deprecated behaviors must function for no less than 1 year after their announced deprecation.", which I'm reading: if we graduate FlavorFungabilityImplicitPreferenceDefault to Beta, then we need to keep it for 1 year in Beta to allow users to return to the old behavior. So, I think the path exists. wdyt?

Still, if you feel strongly about it, I'm ok with API, but I wouldn't like to rush with new APIs. So far all the API proposals I've seen have some drawbacks. So, I'm ok to make the feature gate as "Alpha", but with a note that we intend to replace it with an API. wdyt?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fyi: we synced on slack with @tenzen-y, and we agreed to introduce an alpha feature gate as a temporary measure to collect feedback from users.

However, going forward instead of graduating the feature gate to Beta, we will introduce an API. This will give us more time to design and discuss the API without rushing. We can add a comment to the feature gate that it is not meant for graduation and its role should be replaced with API.

Unless someone proposes an API which everyone loves, but it seems challenging. So far all proposals have some drawbacks IMO.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mimowo Thank you for summarizing our discussion.
As Michal mentioned in the above comment, we introduce a temporary FG (FlavorFungabilityImplicitPreferenceDefault ) for early feedback users for v0,13. However, to avoid the significant specification changes (Borrow -> Preemption), we do not change the behavior as a default. So, we will revist the API consideration for the v0.14. After we define the APIs for new behavior for v0.14, we will remove the FG (FlavorFungabilityImplicitPreferenceDefault).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gabesaba @pajakd Could you address those decisions?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the implementation PR (#6132) accordingly. Now I'll update this PR to include the decisions.

@mimowo
Copy link
Copy Markdown
Contributor

mimowo commented Jul 23, 2025

xref as KEP for #6132

@pajakd please update the descption to say "KEP for #..." or "Part of #..." , then GH would x-ref automatically

@pajakd pajakd marked this pull request as ready for review July 24, 2025 10:59
@k8s-ci-robot k8s-ci-robot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jul 24, 2025
@k8s-ci-robot k8s-ci-robot requested a review from mimowo July 24, 2025 10:59
@mimowo
Copy link
Copy Markdown
Contributor

mimowo commented Jul 24, 2025

/lgtm
/approve
I believe all comments are addressed. We can always follow up if needed.

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Jul 24, 2025
@k8s-ci-robot
Copy link
Copy Markdown
Contributor

LGTM label has been added.

DetailsGit tree hash: 27b2ffca085aa18641a1e08976ac648dd27d09ca

@k8s-ci-robot
Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: mimowo, pajakd

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Jul 24, 2025
@k8s-ci-robot k8s-ci-robot merged commit 5448908 into kubernetes-sigs:main Jul 24, 2025
8 checks passed
@k8s-ci-robot k8s-ci-robot added this to the v0.13 milestone Jul 24, 2025
kannon92 pushed a commit to openshift-kannon92/kubernetes-sigs-kueue that referenced this pull request Aug 11, 2025
)

* Update kep

* Avoid -> prefer

* Strategy -> policy

* Added a new story

* WIP

* Update KEP

* Update story

* Update story

* Remove dependency on FR
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. kind/documentation Categorizes issue or PR as related to documentation. lgtm "Looks good to me", indicates that a PR is ready to be merged. release-note-none Denotes a PR that doesn't merit a release note. size/M Denotes a PR that changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants