Skip to content

Commit 799a911

Browse files
committed
Update with feedback
Signed-off-by: Marvin Beckers <[email protected]>
1 parent 120cef5 commit 799a911

File tree

1 file changed

+30
-26
lines changed

1 file changed

+30
-26
lines changed

designs/multi-cluster.md

+30-26
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Author: @sttts @embik
44

55
Initial implementation: @vincepri
66

7-
Last Updated on: 12/04/2024
7+
Last Updated on: 2025-01-06
88

99
## Table of Contents
1010

@@ -38,7 +38,7 @@ objects. This proposal is about adding native support for multi-cluster use-case
3838
to controller-runtime.
3939

4040
With this change, it will be possible to implement pluggable cluster providers
41-
that automatically start and stop watches (and thus, cluster-aware reconcilers) when
41+
that automatically start and stop sources (and thus, cluster-aware reconcilers) when
4242
the cluster provider adds ("engages") or removes ("disengages") a cluster.
4343

4444
## Motivation
@@ -56,24 +56,27 @@ This change is important because:
5656

5757
### Goals
5858

59-
- Provide an interface for plugging in a "cluster provider", which provides a dynamic set of clusters that should be reconciled by registered controllers.
60-
- Provide a way to natively write controllers that
61-
1. (UNIFORM MULTI-CLUSTER CONTROLLER) operate on multiple clusters in a uniform way,
59+
- Allow 3rd-parties to implement an (optional) multi-cluster provider Go interface that controller-runtime will use (if configured on the manager) to dynamically attach and detach registered controllers to clusters that come and go.
60+
- With that, provide a way to natively write controllers for these patterns:
61+
1. (UNIFORM MULTI-CLUSTER CONTROLLERS) operate on multiple clusters in a uniform way,
6262
i.e. reconciling the same resources on multiple clusters, **optionally**
6363
- sourcing information from one central hub cluster
6464
- sourcing information cross-cluster.
6565

66-
Example: distributed `ReplicaSet` controller, reconciling `ReplicaSets` on multiple clusters.
67-
2. (AGGREGATING MULTI-CLUSTER CONTROLLER) operate on one central hub cluster aggregating information from multiple clusters.
66+
Example: distributed `ReplicaSet` controller, reconciling `ReplicaSets` on multiple clusters.
67+
2. (AGGREGATING MULTI-CLUSTER CONTROLLERS) operate on one central hub cluster aggregating information from multiple clusters.
6868

6969
Example: distributed `Deployment` controller, aggregating `ReplicaSets` across multiple clusters back into a central `Deployment` object.
70-
- Allow clusters to dynamically join and leave the set of clusters a controller operates on.
71-
- Allow logical clusters where a set of clusters is actually backed by one physical informer store.
72-
- Allow 3rd-parties to plug in their multi-cluster adapter (in source code) into
73-
an existing multi-cluster-compatible code-base.
70+
71+
#### Low-Level Requirements
72+
73+
- Allow event sources to be cross-cluster such that:
74+
1. Multi-cluster events can trigger reconciliation in the one central hub cluster.
75+
2. Central hub cluster events can trigger reconciliation on multiple clusters.
76+
- Allow reconcilers to look up objects through (informer) indexes from specific other clusters.
7477
- Minimize the amount of changes to make a controller-runtime controller
7578
multi-cluster-compatible, in a way that 3rd-party projects have no reason to
76-
object these kind of changes.
79+
object to these kind of changes.
7780

7881
Here we call a controller to be multi-cluster-compatible if the reconcilers get
7982
reconcile requests in cluster `X` and do all reconciliation in cluster `X`. This
@@ -231,9 +234,16 @@ if err != nil {
231234
client := cl.GetClient()
232235
```
233236

234-
Due to the BYO `request` type, controllers need to be built like this:
237+
Due to the BYO `request` type, controllers using the `For` builder function need to be built/changed like this:
235238

236239
```golang
240+
// previous
241+
builder.TypedControllerManagedBy[reconcile.Request](mgr).
242+
Named("single-cluster-controller").
243+
For(&corev1.Pod{}).
244+
Complete(reconciler)
245+
246+
// new
237247
builder.TypedControllerManagedBy[ClusterRequest](mgr).
238248
Named("multi-cluster-controller").
239249
Watches(&corev1.Pod{}, &ClusterRequestEventHandler{}).
@@ -243,7 +253,7 @@ builder.TypedControllerManagedBy[ClusterRequest](mgr).
243253
With `ClusterRequest` and `ClusterRequestEventHandler` being BYO types. `reconciler`
244254
can be e.g. of type `reconcile.TypedFunc[ClusterRequest]`.
245255

246-
`ClusterRequest` will likely often look like this:
256+
`ClusterRequest` will likely often look like this (but since it is a BYO type, it could store other information as well):
247257

248258
```golang
249259
type ClusterRequest struct {
@@ -252,18 +262,12 @@ type ClusterRequest struct {
252262
}
253263
```
254264

255-
Controllers that use `For` or `Owns` cannot be converted to multi-cluster controllers
256-
without changing to `Watches` as the BYO `request` type cannot be used with them:
257-
258-
```golang
259-
// pkg/builder/controller.go
260-
if reflect.TypeFor[request]() != reflect.TypeOf(reconcile.Request{}) {
261-
return fmt.Errorf("For() can only be used with reconcile.Request, got %T", *new(request))
262-
}
263-
```
265+
Controllers that use `Owns` cannot be converted to multi-cluster controllers
266+
without a BYO type re-implementation of `handler.EnqueueRequestForOwner` matching
267+
the BYO type, which is considered out of scope for now.
264268

265-
With the described changes (use `GetCluster(ctx, clusterName)` and making `reconciler`
266-
a `TypedFunc[ClusterRequest`) an existing controller will automatically act as
269+
With the described changes (use `GetCluster(ctx, clusterName)`, making `reconciler`
270+
a `TypedFunc[ClusterRequest]` and migrating to `Watches`) an existing controller will automatically act as
267271
*uniform multi-cluster controller*. It will reconcile resources from cluster `X`
268272
in cluster `X`.
269273

@@ -273,7 +277,7 @@ the controller.
273277

274278
Controllers that should be triggered by events on the hub cluster can continue
275279
to use `For` and `Owns` and explicitly pass the intention to engage only with the
276-
"default" cluster:
280+
"default" cluster (this is only necessary if a cluster provider is plugged in):
277281

278282
```golang
279283
builder.NewControllerManagedBy(mgr).

0 commit comments

Comments
 (0)