-
Notifications
You must be signed in to change notification settings - Fork 179
v1.0 InferencePool API Review #1173
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
v1.0 InferencePool API Review #1173
Conversation
Hi @capri-xiyue. Thanks for your PR. I'm waiting for a kubernetes-sigs member to verify that this patch is reasonable to test. If it is, they should reply with Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. |
/hold |
✅ Deploy Preview for gateway-api-inference-extension ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
5317094
to
4ffb5f6
Compare
/hold, this should not get merged |
77371fe
to
4ffb5f6
Compare
Note: This PR is NOT intended to merge, it is entirely for the purpose of API review. |
I lost the comment thread, but I believe I saw something along the lines of:
If that's the case, you can set KALs config for Omitzero support is only for structs in KAL right now, and with it set to forbid, it will force the omitempty route with a pointer for all optional structs |
FYI #1427 is a PR under review that implements several API changes based on feedback from API reviewers here and discussions among the community, maintainers, etc. |
@thockin the challenge I see with inlining is that no field by itself can be used as the map key: type ParentReference struct {
// Group is the group of the referent API object. When unspecified, the referent is assumed
// to be in the "gateway.networking.k8s.io" API group.
//
// +optional
// +kubebuilder:default="gateway.networking.k8s.io"
Group *Group `json:"group,omitempty"`
// Kind is the kind of the referent API object. When unspecified, the referent is assumed
// to be a "Gateway" kind.
//
// +optional
// +kubebuilder:default=Gateway
Kind *Kind `json:"kind,omitempty"`
// Name is the name of the referent API object.
//
// +required
Name ObjectName `json:"name,omitempty"`
// Namespace is the namespace of the referenced object. When unspecified, the local
// namespace is inferred.
...
// +optional
Namespace *Namespace `json:"namespace,omitempty"`
} All fields are needed to ensure the uniqueness of a parent. |
I tried it, with omitzero forbid, https://github.com/kubernetes-sigs/gateway-api-inference-extension/pull/1438/files#diff-8d7db842a7673f66c7db001de9fe07ce67b67e21d8cbce12394fde46eea1e5b7R36 I still need ignore kubeapi linter otherwise it will also show |
Kind is not a struct, it is a string. You have a non-zero minimum length marker on kind so why do we need it to be a pointer? The string being empty implies to the go client that it wasn't present when admitted |
// Status defines the observed state of the InferencePool. | ||
// | ||
// +optional | ||
//nolint:kubeapilinter // status should not be a pointer. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not? It's the same as any other struct
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We followed the existing k8s convention. See https://github.com/kubernetes/api/blob/master/batch/v1/types.go#L84
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@JoelSpeed I agree that Status should be a pointer type, but we could not find other K8s APIs that follow this convention. We prefer to follow established patterns.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In theory every optional struct-field should be a pointer. In practice, we do not do that (in part because we have had no linter).
I am OK with this because it is "not worse than" everything else in the system. We should refine the rules (the doc which emerged from this discussion)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Joel, are you OK to resolve this one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should preserve the right to the projects to decide to switch to the new conventions meanwhile they adhere to the long established patterns that we know are safe
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm ok with adding an exception, but can we please use the more specific golangci-lint exceptions in the config file that ignore specific messages rather than blanket ignoring the whole KAL suite for this field?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@JoelSpeed can you share a pointer for how we could do that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apologies for getting to this so late, but, an example would be how CAPI has done so, https://github.com/kubernetes-sigs/cluster-api/blob/0db4bf4fd9ec5cea39d1853fd4b2e877788b46df/.golangci-kal.yml#L86-L91
It's directly in the golangci config with a path regex and text regex to match on.
Further to my comment above, did we decide all optional fields should be pointers, or, only optional structs? Cc @robscott I thought the latter, but the exceptions I'm seeing imply the former Either decision can be configured in KAL so we shouldn't need any exceptions apart from the port number where a specific decision was made to ignore the guidance about the zero value |
Note that when the API is approved, we need to resolve #1424. |
We are trying to provide consistency with Gateway API, where Kind is a pointer (xref). @robscott it's my understanding that kubeapilinter is being used in the Gateway API repo. If so, is |
Map keys can be a set of fields, they just can't be deeper nested. |
// Status defines the observed state of the InferencePool. | ||
// | ||
// +optional | ||
//nolint:kubeapilinter // status should not be a pointer. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Joel, are you OK to resolve this one?
apix/v1/inferencepool_types.go
Outdated
Name ObjectName `json:"name,omitempty"` | ||
|
||
// PortNumber is the port number of the Endpoint Picker extension service. When unspecified, | ||
// implementations SHOULD infer a default value of 9002 when the kind field is "Service" or |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rob, we discussed this, but I forget what we came to. Do we have good precedent for "should infer" as opposed to just setting a default?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To clarify, the default value of 9002 only applies when the kind filed is a service or unspecified (defaults to "Service").
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My point is that telling clients to infer a value is generally not what we do. We either give it an explicit default or we require the user to set it.
You can bundle an MAP which looks at Group and Kind, and assigns 9002, but the validation for it would be "required". Or you can assign a static default of 9002 and leave it optional.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cc @robscott for the context of inferring here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry I'd forgotten about this one! Fundamentally we're trying to leave room open for a type of backend where port defined at this level would either be meaningless or repetitive. IE imagine that we want to point to a different kind of backend that only ever has one port, and that port is inferred by the type. Why would we require port here?
We could follow the model that Gateway API uses here which would be to require port in cases where it's ambiguous, such as multi-port Services. With that said, unlike Gateway API, we already know that the most common case will be a Service listening on port 9002, so it seems like a shame to require that input from users in the common case.
Unfortunately "only require a field when the target has multiple ports, and one of them is not 9002" is not something that I can find a good way to express with any of the validations we have available to us today.
You can bundle an MAP which looks at Group and Kind, and assigns 9002
I think that makes a lot of sense as MAP becomes more broadly available, but it will still be in alpha when this release happens. We can file a follow up issue to bundle a MAP when it reaches beta.
So that's a long way of saying that I think the current state is the least bad way to achieve the following combination:
- Sensible defaults that cover the common case and avoid unnecessary inputs - this default can be translated from controller-inferred to MAP in the future as it's available
- Room for targeting other backend types where port would not be meaningful
- Consistency with existing APIs (alpha version of this API + Gateway API BackendRef)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have seen no other APIs do this
Obviously very biased here, but IMO this same pattern has worked reasonably well for Gateway API. Some examples of where this has been valuable:
- GKE, Envoy Gateway, and others support targeting ServiceImport from Routes to effectively provide "Multi-Cluster Gateways"
- AgentGateway uses Gateway API Routes and targets a custom MCP Backend type
- Gateway for Mesh is based on a creative use of
parentRefs
on Routes. See Istio's docs for an example, but this pattern has become widespread across meshes
Carrying this a fuller normalization, why is it not even more abstract, like
type EndpointPicker struct {
// One of the following must be specified
// A reference to a kubernetes Service
Service *ServiceRef
// An arbitrary thing on the network
Network *NetworkRef
// A reference to an arbitrary kubernetes object
Object *ObjectRef
Doesn't the presence of ObjectRef
in that example invalidate the idea of ServiceRef
? It would provide more than one way to point to a Service which feels suboptimal. If on the other hand we exclude ObjectRef
, we're missing out on some very real opportunity for innovation and extension from the implementations of this API. Honestly I think one of the strongest parts of Gateway API is that there's a well defined core with plenty of extension points that allow you to plug in your own custom type of Route or Backend while still retaining the rest of the API. I'd hate to give that up here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some examples of where this has been valuable
What is "this". To me "this" is defining an implcit default value in the documentation, and imposing that work on clients and/or implementations.
Doesn't the presence of ObjectRef in that example invalidate the idea of ServiceRef?
No - a ServiceRef can a) be simpler and b) carry more assumptions. You don't need group or kind, and you can safely assume that "port" is meaningful. Or you can just assert a fixed port number (maybe?). You can, of course, represent a Service as an ObjectRef, but the API is less precise and more generic.
I'm not saying to necessarily do exactly this, I am saying that an implicit, conditional default is more than a little bit smelly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Chatted offline with @thockin and we agreed that although this is not perfect, mirroring Gateway API behavior here is a reasonable path. That means two things:
- We should remove the inferred default of 9002
- We should require port to be specified when the target kind is Service (this will require some CEL validation)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change needed is included in #1484
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've updated PR to reflect the change. Let me know whether it works now or not.
apix/v1/inferencepool_types.go
Outdated
// | ||
// +optional | ||
//nolint:kubeapilinter // ignore kubeapilinter here as we want to use pointer as zero means all ports in convention, we don't make to use 0 to indicate not set. | ||
PortNumber *PortNumber `json:"portNumber,omitempty"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why "PortNumber" vs "Port" ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will we need protocol here eventually? Did we discuss this one?
Why not use the same Port struct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@robscott Do you have any context about this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. I think the ideal would be to mirror BackendObjectReference
in GW API where we have a port
field with the same validation instead of portNumber
. I think this started as portNumber
to avoid any confusion over portName
, but given that we've used port
successfully for years in GW API without any issues or need for struct/other fields, I'd expect that to work well here as well.
I'm a bit split on whether or not we should make the change from portNumber
to port
at this late stage. Will defer to @danehans, @kfswain, and @nirrozenbaum.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’m fine with this change. portNumber was introduced only in v1 (different field exists in v1alpha2) and as long as the api has not been finalized, that’s ok to change.
we do need to keep in mind that v1 rc1 was already cut, but if we feel strongly that this is an improvement let’s go for it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the PR of approach 3 to make two different ports symmetric #1484
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why "PortNumber" vs "Port" ?
To reduce the nesting within EndpointPickerRef
. To your point, if named ports and app protocol are anticipated future requirements, then +1 to use type Port
instead of PortNumber
. Currently, this spec defines the Gateway <> EPP protocol as ext-proc (gRPC), so I'm unsure if any additional app protocols are needed. Thoughts @robscott @kfswain @nirrozenbaum
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've updated PR to reflect the change. Let me know whether it works now or not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, +1. I think further app protocols may be useful at some point in the future, but it's not necessary now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned by @capri-xiyue, this has been addressed by #1484.
@capri-xiyue: The following test failed, say
Full PR test history. Your PR dashboard. Please help us cut down on flakes by linking to an open issue when you hit one in your PR. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
/lgtm
/approve
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: capri-xiyue, thockin The full list of commands accepted by this bot can be found here.
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
may we close this as completed? |
Yep, thanks @nirrozenbaum! /close |
@robscott: Closed this PR. In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. |
What type of PR is this?
/kind api-change
What this PR does / why we need it:
This PR is a diff of /apis from alpha (main branch) to v1.0 (release-1.0 branch).
Note: This PR is purely to facilitate review, it is not intended to merge.
Changes:
/assign @robscott