-
Notifications
You must be signed in to change notification settings - Fork 39k
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
Places for hooks #3585
Comments
We discussed this today in the meeting @derekwaynecarr @smarterclayton We discussed this in our office yesterday @bgrant0607 |
Does default-value expansions count as one of these? It wants to (but Why must apiserver hooks be built in? Could we not support exec hooks that
|
@thockin |
LGTM, maybe this can become a design doc for future reference? |
I am on cell, so brief. I thought about defaulting, but I think it is too I think exec hooks are reasonable, with constraints that exec is much I think ~all extension points should have an exec side-load.
|
I basically like this proposal, just a few comments/questions
|
@davidopp - Admission control is not a finalizer for the reason you stated - it provides immediate success/failure response to the end-user. |
Another option: webhooks |
See also: #1502 (comment) |
Meaning, the API server makes some call out to an HTTP endpoint? This could work but I believe it requires putting the logic about handoff, graceful degradation, etc. inside the API server rather than the finalizer, which may not be good for modularity. The API server would need to know the identity of all of the finalizers, though of course that could be configurable (though you'd need some way to have it re-read the config when it changes, versus the finalizer approach Eric described allows the API server to not need to know anything about the finalizers.) |
We have a lot of experience with the "finalizer" approach. It permits loosely coupled, choreographed interaction between components. Main cons are understandability when things go wrong, as @erictune mentioned, operational complexity, auth. complexity (who's allowed to munge what), lack of centralized control (if you want/need that), latency, and bootstrapping complexity. |
BTW, I don't mean to sound down on finalizers. In balance, they've worked pretty well. |
I think "Put it in the apiserver if the act of persisting of the object could be harmful" is the only strong justification to not use the finalizer approach (assuming we use it for anything). We already support async operations. We could not declare creation operations done until finalization. We've had requests for this from people working on deployment tools, similar to the use cases in #1899. Certainly higher-level deployment, scheduling, and workflow systems will want to be able to respond to conditions such as pods not scheduling. Also, I'd like a |
API plugins are related: #991 |
I think probably the finalizer and call-out approaches end up with the same set of issues. In fact, if you structure the call-outs as API server plug-ins, then there's probably not much difference between the two approaches at all. It's just a question of whether the logic for how these pieces of logic interact (e.g. for sequencing) is running in one process (the api server) or is distributed across multiple processes (finalizers). In Google's cluster management system we use a mixture of the two approaches and I'm not sure I'd say one is obviously better than the other. |
Sounds like we need a good proposal for finalizer (concrete, lays out how the scheduler knows when to run, hashes out what a small cluster solution would look like), and then we should consider doing that post 1.0? Also, authorization is another operation that could be done via call-out early in admission control for user actions (vs as a proxy). We talked about remoting the authz check for some use cases without requiring a proxy, and at that point it looks a lot more like a call out. Call out actions do not necessarily require auth, since they are a higher power. And after creation, authorization is the only thing that has control over what mutations are made post creation, so authorization checks have to be per field (and determine the difference between mutating a field, vs setting it). Ie my post creation watcher might set volumes but not networking, but if I shouldn't be able to edit networking the authz check has to discriminate between "field changed" and "field unchanged". I don't see an easy way to do that unless you have the existing object loaded, which means a proxy won't have the necessary info available.
|
@brendandburns suggested using a "finalizer" for allocating IP addresses in issue #3435 |
Finalizers need to be replicated for availability. When one fails, or is overloaded, the others need to pick up the work it was doing without leaving anything forgotten. In some cases, there may be multiple finalizers that could work on an object. We could impose a specific ordering. But if one is not necessary, we could allow them freedom to work in an arbitrary order. But they need to not waste time doing work, only to find that the object has changed underneath them. One pattern that would address both problems is if finalizers could take out "leases" on objects, for say a few seconds, while they work on them. Apiserver would enforce leases. Needs more thought. |
Thanks @erictune for putting this proposal up for review +1 for the use cases discussed here, especially admissions control and networking related (custom ip allocation, setting up vlans/bridged-networks, etc.) For my clarification, on implementation of these hooks, if they are expected to be:
|
As @smarterclayton said, we still need to have a more concrete proposal for that, and work on that should wait until after we ship 1.0. But, if you want to hack something up before then as a proof of concept, with the understanding that we might change our minds, that would be cool. I suggest that you do the following:
|
FWIW from my experience: it's worth erring on the side of centralized control and only making things loosely coupled when you actually have something that's totally async and orthogonal to the rest of the system. Building these systems is complex, and making them loosely coupled adds to that complexity. The points raised by a few people above are worth reiterating: it's a PITA to figure out what's happening when things don't work as you expect. I suspect that mostly comes from the number of possible execution orders -- it's not A then B then C, it's some arbitrary order -- so convincing yourself that the code works as intended is hard. You have to make sure not only that an execution order is correct, but that all possible ones are. |
@alex-mohr - your concern is well founded. Trying to keep it too generic/futuristic is neither needed, nor worth it. That said, I'd not confuse that with taking complexity out of the core function - I believe simplifying the core to not get muddled with unwanted details and keep it stable from forever changing requirements is a very good goal. Let's take an example: having following two or three hooks for networking, would suffice the current implementation and requirements for networking:
While keeping the default simplicity of network model as is, it can allow somewhat advanced/different use cases (#3550) to be implemented, in the plugins, with the help of hooks such that the core is not affected. To me, this keeps the design stable and simple for longer run. I hope you'd agree that the use cases for networking that I brought are worth addressing in order to increase the adoption of Kubernetes. |
@bgrant0607 - I have not had time to think about how synchronous delegation would work yet, and ma not until we look at 1.2 |
@derekwaynecarr We're definitely not going to look at this until 1.2. Our current leaning is to do as much as possible asynchronously, though. |
@bgrant0607 - I was asked about a use case today to see if it would be That said I continue to still get asked for sequential set of url hooks I think a good goal for 1.2 is to make the initial resources autosizing On Thursday, October 15, 2015, Brian Grant notifications@github.com wrote:
|
On the dependencies/ordering side I wonder if the semantics of systemd's unit files would also make sense in this context. Unit files can express pure dependencies, which don't enforce an ordering, and 'liberal' ordering which only enforces ordering if the dependency is present. Combining both leads to hard dependencies with ordering. However the ownership issue, to prevent that multiple finalizers/initializers/hooks fight over the same resource or field path. My main interest in this topic are primarily admission controllers. |
I think the systemd dependency model in unit files is both simple and effective, in particular the useful distinction between strict |
This is effectively part of 1.7, future work there will improve it. Closing as part of 1.7 (see kubernetes/community#132) |
There are lots of reasons why the "system" wants to look at an object, like a pod, and modify and/or act on it. There are also a number of places where we can put in "hooks" for these actions. We'll end up with a better system in the long run, I think, if we put some thought into what hooks to use in what situations.
Places for hooks
Within apiserver, there are both hardcoded actions on objects, and extensible ones (such as what @derekwaynecarr has implemented with "admission control", #3472 and #3319).
The last one is a somewhat new concept, so it deserves a bit of explanation. After a pod is POST'ed to the apiserver, and persisted to etcd, some other component (a different process than apiserver), which is watching for new objects, will see it, and act on it and/or modify it. It should not start running on a Kubelet until all the things that need to act on it have done so. @smarterclayton called this a "finalizer". The scheduler can be viewed as a finalizer that takes pods that have everything except a HostIP set, and it sets the HostIP.
Pros/cons of each hook location
Use cases for hooked actions
Which hooks to use for what
Suggested guidelines for what hooks to use for what types of actions
Next steps
On finalizers from #3586
Read #3585 too.
We should have a general framework for a pod or other object to be POST'ed in an incomplete state, and persisted to etcd, and then subsequently to be handled by a series of "finalizers" that fill in missing fields. Once all are filled in, the object can be picked up by a kubelet and run.
Use cases
Use cases for filling in fields in pods after they are stored.
Availability
Availability of the cluster limited by the finalizers, so they need to be replicated. Fortunately, because they typically act on one object at a time, and can use resource versioning, it should be easy to parallelize them.
Bootstrapping
There has to be some way to get pods onto minions without waiting for finalizers to act on them, when turning up a cluster, or upgrading a finalizer. The scheduler is a special case of this.
Some options:
State and sequence
The text was updated successfully, but these errors were encountered: