|
| 1 | +/* |
| 2 | +Copyright 2018 The Kubernetes Authors. |
| 3 | +
|
| 4 | +Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | +you may not use this file except in compliance with the License. |
| 6 | +You may obtain a copy of the License at |
| 7 | +
|
| 8 | + http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | +
|
| 10 | +Unless required by applicable law or agreed to in writing, software |
| 11 | +distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | +See the License for the specific language governing permissions and |
| 14 | +limitations under the License. |
| 15 | +*/ |
| 16 | + |
| 17 | +/* |
| 18 | +Package pkg provides libraries for building Controllers. Controllers implement Kubernetes APIs |
| 19 | +and are central to building Operators, Workload APIs, Configuration APIs, Autoscalers, and more. |
| 20 | +
|
| 21 | +Client |
| 22 | +
|
| 23 | +Client provides a Read / Write client for reading and writing objects to an apiserver. |
| 24 | +
|
| 25 | +Cache |
| 26 | +
|
| 27 | +Cache provides a Read client for reading objects from an apiserver that are stored in a local cache. |
| 28 | +Cache supports registering handlers to respond to events that update the cache. |
| 29 | +
|
| 30 | +Manager |
| 31 | +
|
| 32 | +Manager provides a mechanism for Starting components and provides shared Caches and Clients to the components. |
| 33 | +
|
| 34 | +Controller |
| 35 | +
|
| 36 | +Controller is a work queue that enqueues work in response to source.Source events (e.g. Pod Create, Update, Delete) |
| 37 | +and triggers reconcile.Reconcile functions when the work is dequeued. |
| 38 | +
|
| 39 | +Unlike http handlers, Controllers DO NOT perform work directly in response to events, but instead enqueue |
| 40 | +reconcile.Requests so the work is performed eventually. |
| 41 | +
|
| 42 | +* Controllers run reconcile.Reconcile functions against objects (provided as name / Namespace). |
| 43 | +
|
| 44 | +* Controllers enqueue reconcile.Requests in response events provided by source.Sources. |
| 45 | +
|
| 46 | +Reconcile |
| 47 | +
|
| 48 | +reconcile.Reconcile is a function that may be called at anytime with the Name and Namespace of an |
| 49 | +object. When called, it will ensure that the state of the system matches what is specified in the object at the |
| 50 | +time Reconcile is called. |
| 51 | +
|
| 52 | +Example: Reconcile is run against a ReplicationController object. The ReplicationController specifies 5 replicas. |
| 53 | +3 Pods exist in the system. Reconcile creates 2 more Pods and sets their OwnerReference to point at the |
| 54 | +ReplicationController. |
| 55 | +
|
| 56 | +* reconcile works on a single object type. - e.g. it will only reconcile ReplicaSets. |
| 57 | +
|
| 58 | +* reconcile is triggered by a reconcile.Request containing the name / Namespace of an object to reconcile. |
| 59 | +
|
| 60 | +* reconcile does not care about the event contents or event type triggering the reconcile.Request. |
| 61 | +- e.g. it doesn't matter whether a ReplicaSet was created or updated, reconcile will check that the correct |
| 62 | +Pods exist either way. |
| 63 | +
|
| 64 | +* Users MUST implement Reconcile for Controllers. |
| 65 | +
|
| 66 | +Source |
| 67 | +
|
| 68 | +resource.Source provides a stream of events. Events may be internal events from watching Kubernetes |
| 69 | +APIs (e.g. Pod Create, Update, Delete), or may be synthetic Generic events triggered by cron or WebHooks |
| 70 | +(e.g. through a Slackbot or GitHub callback). |
| 71 | +
|
| 72 | +Example 1: source.Kind uses the Kubernetes API Watch endpoint for a GroupVersionKind to provide |
| 73 | +Create, Update, Delete events. |
| 74 | +
|
| 75 | +Example 2: source.Channel reads Generic events from a channel fed by a WebHook called from a Slackbot. |
| 76 | +
|
| 77 | +* source provides a stream of events for EventHandlers to handle. |
| 78 | +
|
| 79 | +* source may provide either events from Watches (e.g. object Create, Update, Delete) or Generic triggered |
| 80 | +from another source (e.g. WebHook callback). |
| 81 | +
|
| 82 | +* Users SHOULD use the provided Source implementations instead of implementing their own for nearly all cases. |
| 83 | +
|
| 84 | +EventHandler |
| 85 | +
|
| 86 | +eventhandler.EventHandler maps from a source.Source into reconcile.Requests which are enqueued as work for the |
| 87 | +Controller. |
| 88 | +
|
| 89 | +Example: a Pod Create event from a Source is provided to the eventhandler.EnqueueHandler, which enqueues a |
| 90 | +reconcile.Request containing the name / Namespace of the Pod. |
| 91 | +
|
| 92 | +* EventHandler takes an event.Event and enqueues reconcile.Requests |
| 93 | +
|
| 94 | +* EventHandlers MAY map an event for an object of one type to a reconcile.Request for an object of another type. |
| 95 | +
|
| 96 | +* EventHandlers MAY map an event for an object to multiple reconcile.Requests for different objects. |
| 97 | +
|
| 98 | +* Users SHOULD use the provided EventHandler implementations instead of implementing their own for almost all cases. |
| 99 | +
|
| 100 | +Predicate |
| 101 | +
|
| 102 | +predicate.Predicate allows events to be filtered before they are given to EventHandlers. This allows common |
| 103 | +filters to be reused and composed together with EventHandlers. |
| 104 | +
|
| 105 | +* Predicate takes and event.Event and returns a bool (true to enqueue) |
| 106 | +
|
| 107 | +* Predicates are optional |
| 108 | +
|
| 109 | +* Users SHOULD use the provided Predicate implementations, but MAY implement their own Predicates as needed. |
| 110 | +
|
| 111 | +PodController Diagram |
| 112 | +
|
| 113 | +Source provides event: |
| 114 | +
|
| 115 | +* &source.KindSource{"core", "v1", "Pod"} -> (Pod foo/bar Create Event) |
| 116 | +
|
| 117 | +EventHandler enqueues Request: |
| 118 | +
|
| 119 | +* &eventhandler.Enqueue{} -> (reconcile.Request{"foo", "bar"}) |
| 120 | +
|
| 121 | +Reconcile is called with the Request: |
| 122 | +
|
| 123 | +* Reconcile(reconcile.Request{"foo", "bar"}) |
| 124 | +
|
| 125 | +Usage |
| 126 | +
|
| 127 | +The following example shows creating a new Controller program which Reconciles ReplicaSet objects in response |
| 128 | +to Pod or ReplicaSet events. The Reconcile function simply adds a label to the ReplicaSet. |
| 129 | +
|
| 130 | +See the example/main.go for a usage example. |
| 131 | +
|
| 132 | +Controller Example |
| 133 | +
|
| 134 | +1. Watch ReplicaSet and Pods Sources |
| 135 | +
|
| 136 | +1.1 ReplicaSet -> eventhandler.EnqueueHandler - enqueue the ReplicaSet Namespace and Name. |
| 137 | +
|
| 138 | +1.2 Pod (created by ReplicaSet) -> eventhandler.EnqueueOwnerHandler - enqueue the Owning ReplicaSet key. |
| 139 | +
|
| 140 | +2. Reconcile ReplicaSet |
| 141 | +
|
| 142 | +2.1 ReplicaSet object created -> Read ReplicaSet, try to read Pods -> if is missing create Pods. |
| 143 | +
|
| 144 | +2.2 reconcile triggered by creation of Pods -> Read ReplicaSet and Pods, do nothing. |
| 145 | +
|
| 146 | +2.3 reconcile triggered by deletion of Pods -> Read ReplicaSet and Pods, create replacement Pods. |
| 147 | +
|
| 148 | +Watching and EventHandling |
| 149 | +
|
| 150 | +Controllers may Watch multiple Kinds of objects (e.g. Pods, ReplicaSets and Deployments), but they should |
| 151 | +enqueue keys for only a single Type. When one Type of object must be be updated in response to changes |
| 152 | +in another Type of object, an EnqueueMappedHandler may be used to reconcile the Type that is being |
| 153 | +updated and watch the other Type for Events. e.g. Respond to a cluster resize |
| 154 | +Event (add / delete Node) by re-reconciling all instances of another Type that cares about the cluster size. |
| 155 | +
|
| 156 | +For example, a Deployment controller might use an EnqueueHandler and EnqueueOwnerHandler to: |
| 157 | +
|
| 158 | +* Watch for Deployment Events - enqueue the key of the Deployment. |
| 159 | +
|
| 160 | +* Watch for ReplicaSet Events - enqueue the key of the Deployment that created the ReplicaSet (e.g the Owner) |
| 161 | +
|
| 162 | +Note: reconcile.Requests are deduplicated when they are enqueued. Many Pod Events for the same ReplicaSet |
| 163 | +may trigger only 1 reconcile invocation as each Event results in the Handler trying to enqueue |
| 164 | +the same reconcile.Request for the ReplicaSet. |
| 165 | +
|
| 166 | +Controller Writing Tips |
| 167 | +
|
| 168 | +Reconcile Runtime Complexity: |
| 169 | +
|
| 170 | +* It is better to write Controllers to perform an O(1) reconcile N times (e.g. on N different objects) instead of |
| 171 | +performing an O(N) reconcile 1 time (e.g. on a single object which manages N other objects). |
| 172 | +
|
| 173 | +* Example: If you need to update all Services in response to a Node being added - reconcile Services but Watch |
| 174 | +Node events (transformed to Service object name / Namespaces) instead of Reconciling the Node and updating all |
| 175 | +Services from a single reconcile. |
| 176 | +
|
| 177 | +Event Multiplexing: |
| 178 | +
|
| 179 | +* reconcile.Requests for the same name / Namespace are deduplicated when they are enqueued. This allows |
| 180 | +for Controllers to gracefully handle event storms for a single object. Multiplexing multiple event Sources to |
| 181 | +a single object type takes advantage of this. |
| 182 | +
|
| 183 | +* Example: Pod events for a ReplicaSet are transformed to a ReplicaSet name / Namespace, so the ReplicaSet |
| 184 | +will be Reconciled only 1 time for multiple Pods. |
| 185 | +*/ |
| 186 | +package pkg |
0 commit comments