-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
Standard API qps and burst in kubeconfig file. #1629
Conversation
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: deads2k The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
@deads2k: 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/test-infra repository. I understand the commands that are listed here. |
type AuthInfo struct { | ||
// ... | ||
// QPS indicates the maximum QPS to the master from this client. | ||
// If it's zero, the created RESTClient will use DefaultQPS: 5 |
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.
should we clarify a negative QPS will turn off the ratelimiting in the doc?
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.
"Set to -1 to turn off rate limiting. A value of 0 means to use the default limit from the client binary."
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.
-1 can be even confusing given that the QPS is a float32. what's supposed to happen it's other negative values than -1?
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.
Agree with others, clarify how to turn it off, clarify what negative numbers do (if not that).
I don't really want to make this super more complicated than necessary, but making this into a union/one-of block might make sense.
## Summary | ||
|
||
Kubernetes REST clients use a simple token bucket rate limiter to control the pace of requests from a client. | ||
We will expose the values already present in the [REST config](https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/client-go/rest/config.go#L114-L120), via a kubeconfig file inside the client stanza. |
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.
Line numbers are not stable in the master branch. For a long-lived document like this, it would be better to reference a particular commit. The following URL references the commit to which the master
branch currently points. This URL also skips the staging junk, but still suffices to direct the reader to the intended content.
## Summary | ||
|
||
Kubernetes REST clients use a simple token bucket rate limiter to control the pace of requests from a client. | ||
We will expose the values already present in the [REST config](https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/client-go/rest/config.go#L114-L120), via a kubeconfig file inside the client stanza. |
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.
"via a kubeconfig file inside the client stanza" sounds like it is referring to a kubeconfig file that is inside some client stanza --- but I do not think this is what's meant here. I think what's meant is more like "via the user definitions in kubeconfig files". Alternatively, perhaps what is meant is more like "via a kubeconfig file that is added to a ServiceAccount's Secret".
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 will expose the values already present in the [REST config](https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/client-go/rest/config.go#L114-L120), via a kubeconfig file inside the client stanza. | |
We will expose the values already present in the [REST config](https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/client-go/rest/config.go#L114-L120), in the client stanza of a kubeconfig file. |
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.
you mean "a user stanza"?
|
||
## Proposal | ||
|
||
Add to the `AuthInfo` section of a kubeconfig. |
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 in the preferences
? That would merge just fine and not involve the complicated (and poorly documented) logic involved in merging users --- which does not even meet the need 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.
Why not in the
preferences
? That would merge just fine and not involve the complicated (and poorly documented) logic involved in merging users --- which does not even meet the need here.
That's a dead field.
This identity spans all the contexts with different namespaces, so it is a closer logical match. | ||
You don't generally want different QPS characteristics based on namespace. | ||
|
||
```go |
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.
Please include a URL or k/k-relative pathname for the file where this mod would apply.
### in-cluster kubeconfig overrides | ||
The in-cluster config is the automatic configuration that exists within pods. | ||
The client code itself can be written to consume an overrides.kubeconfig file, which will be merged with the standard | ||
kubeconfig merging rules that we use the env var path today. |
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.
The merging rules we have today do not allow adding/modifying fields within a user. The first specification of that user is taken as a whole and no part is overridden.
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.
The merging rules we have today do not allow adding/modifying fields within a user. The first specification of that user is taken as a whole and no part is overridden.
No, we merge all of it: https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/client-go/tools/clientcmd/loader.go#L226-L252
You're probably used to selection, but merging is also a thing.
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.
Yes, I looked at that code. You see I raised issues with the poor comment on that function (kubernetes/kubernetes#91092) and the poor user-facing documentation about this (kubernetes/website#20967).
The code in question does not itself answer the question, it just makes a two-handed pile of invocations of mergo.MergeWithOverwrite
. The comments on that suggest that merging will be done, but the implementation does not do that. The implementation does not simply look at each layer of structure independently. In the case of a map, the behavior depends on the type of each value. In the case of a map entry whose value is a struct or pointer, the implementation gets to https://github.com/imdario/mergo/blob/v0.3.5/merge.go#L143 --- which replaces the whole value without recursing into it.
I tested, and indeed found that when merging two kubeconfig files that define different fields for a certain user, the result is only the fields of the first kubeconfig file to define that user.
} | ||
``` | ||
|
||
### in-cluster kubeconfig overrides |
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.
The vision here is not entirely clear. I suspect the idea is that the Secret of a ServiceAccount would be extended to have a data member named overrides.kubeconfig
containing a kubeconfig file that specifies the QPS and Burst and nothing else, and that anyone who wants to exercise this control has to create a controller that modifies all the ServiceAccount Secret objects. Have I got this right? If so, that's pretty painful to use and requires a controller with extreme privilege.
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.
Have I got this right? If so, that's pretty painful to use and requires a controller with extreme privilege.
Yeah, but anything we do is going to require mutation of that same secret. It isn't to be taken lightly in general. This is about making it possible, I don't think easy is needed.
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 QPS limit has to be a property of the service account, so this does seem necessary.
Maybe it's not the only model though, I'll make another comment.
### Graduation Criteria | ||
|
||
The API itself is well-known since near the beginning of kube. | ||
We are simply exposing existing values, it will enter as GA. |
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.
There is significant novelty here, in the override mechanism.
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.
There is significant novelty here, in the override mechanism.
I don't think so. I built this pre-1.0 so the merging code already exists. This is just about the expression of what merges.
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.
Things are different today, I hear every mother say.
|
||
1. Connecting to the kube-apiserver to retrieve a value for default QPS and burst. | ||
No default value is going to be good across all workloads. | ||
It's also mechanicaly weird to create a client to get a client. |
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 agree this is a bit weird, but it wouldn't have to be a separate request-- we could make apiserver set a header with its desired rate limit, and the client just obeys it after the first request. This might be simpler?
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 am actually liking this (return a header) more the longer I think about it. Since we have to recompile all clients anyway...
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.
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.
After more thought I think this is too heavyweight (on API changes -- but so is the main proposal), and it's easy to believe that not all clients would want the same rate limit.
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.
(So I guess this would still be in consideration if it were just about turning off the rate limit, not about setting it.)
|
||
## Implementation History | ||
|
||
## Drawbacks |
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.
Do other, non-go clients parse kubeconfig files?
I assume repeated invocations of kubectl would not respect the limits in aggregate?
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 this is aimed at long-lived clients rather than kubectl. I would not expect client-side rate limits to be relevant to kubectl.
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 would not expect that either, but users who see the settings in their kubeconfig files might.
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 proposal allows new content in the kubeconfig files that users hold, but does not require it in general nor in the motivating scenario in particular.
|
||
### Goals | ||
|
||
1. Allow easy and consistent configuration for the existing client-side rate limiting. |
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.
Is this our goal, or is our goal to get rid of it completely?
Is this necessary only transitionally, or forever?
|
||
## Drawbacks | ||
|
||
## Alternatives |
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.
Another alternative might be to plumb these via env var. That'd be gross, but very direct.
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.
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.
The go team tends to do things this way, e.g. for disabling their home grown DNS resolver, and also for disabling HTTP2 I think.
The benefit of this is that it only requires one component to change, no API is baked in, we can remove the env var without breaking people who are setting it.
The downside is that it's not very discoverable (but maybe that's OK since we mostly want to use it to run tests).
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.
Anyone setting this should also look at the client's metrics to verify that it's not spending any time blocked on the QPS limiter (I think there's already a metric).
@deads2k, @liggitt, and I have agreed on the "pre-deprecated, global env var" approach. That is, we'll make the client library check for an environment variable and avoid installing the rate limiter if it is set to some value. The purpose of doing it this way is to avoid committing to an API since we aren't sure it'll be useful for a long period of time. So, we will do this with the env var already deprecated and remove it without warning. Since this won't be a user-visible feature we don't plan on making a KEP for this. |
Agreed /close |
@deads2k: 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/test-infra repository. |
Standard API qps and burst in kubeconfig file.
This allows consistent configuration of all client binaries's QPS and burst settings. This becomes more important now that API priority and fairness is alpha and we want people to try it.