Skip to content

Commit bdb3e3f

Browse files
author
Mengqi Yu
committed
✨ support HA components in controller manager
HA runnable such as webhook server can be run in this mode
1 parent 75a92c7 commit bdb3e3f

File tree

3 files changed

+47
-5
lines changed

3 files changed

+47
-5
lines changed

pkg/manager/internal.go

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,11 @@ type controllerManager struct {
5252
scheme *runtime.Scheme
5353

5454
// runnables is the set of Controllers that the controllerManager injects deps into and Starts.
55+
// These Runnables are managed by lead election.
5556
runnables []Runnable
57+
// haRunnables is the set of webhook servers that the controllerManager injects deps into and Starts.
58+
// These Runnables are in HA mode (not blocked by lead election)
59+
haRunnables []Runnable
5660

5761
cache cache.Cache
5862

@@ -114,8 +118,13 @@ func (cm *controllerManager) Add(r Runnable) error {
114118
return err
115119
}
116120

117-
// Add the runnable to the list
118-
cm.runnables = append(cm.runnables, r)
121+
// Add the runnable to the HA or the leader election list
122+
if haRunable, ok := r.(HARunnable); ok && haRunable.IsHARunnable() {
123+
cm.haRunnables = append(cm.haRunnables, r)
124+
} else {
125+
cm.runnables = append(cm.runnables, r)
126+
}
127+
119128
if cm.started {
120129
// If already started, start the controller
121130
go func() {
@@ -237,6 +246,8 @@ func (cm *controllerManager) Start(stop <-chan struct{}) error {
237246
go cm.serveMetrics(cm.internalStop)
238247
}
239248

249+
go cm.startHA()
250+
240251
if cm.resourceLock != nil {
241252
err := cm.startLeaderElection()
242253
if err != nil {
@@ -256,7 +267,7 @@ func (cm *controllerManager) Start(stop <-chan struct{}) error {
256267
}
257268
}
258269

259-
func (cm *controllerManager) start() {
270+
func (cm *controllerManager) startHA() {
260271
cm.mu.Lock()
261272
defer cm.mu.Unlock()
262273

@@ -274,6 +285,24 @@ func (cm *controllerManager) start() {
274285
// TODO(community): Check the return value and write a test
275286
cm.cache.WaitForCacheSync(cm.internalStop)
276287

288+
// Start the HA runnables after the cache has synced
289+
for _, c := range cm.haRunnables {
290+
// Controllers block, but we want to return an error if any have an error starting.
291+
// Write any Start errors to a channel so we can return them
292+
ctrl := c
293+
go func() {
294+
cm.errChan <- ctrl.Start(cm.internalStop)
295+
}()
296+
}
297+
298+
cm.started = true
299+
}
300+
301+
func (cm *controllerManager) start() {
302+
// Wait for the caches to sync.
303+
// TODO(community): Check the return value and write a test
304+
cm.cache.WaitForCacheSync(cm.internalStop)
305+
277306
// Start the runnables after the cache has synced
278307
for _, c := range cm.runnables {
279308
// Controllers block, but we want to return an error if any have an error starting.

pkg/manager/manager.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,11 @@ import (
4242
// Manager initializes shared dependencies such as Caches and Clients, and provides them to Runnables.
4343
// A Manager is required to create Controllers.
4444
type Manager interface {
45-
// Add will set reqeusted dependencies on the component, and cause the component to be
45+
// Add will set requested dependencies on the component, and cause the component to be
4646
// started when Start is called. Add will inject any dependencies for which the argument
47-
// implements the inject interface - e.g. inject.Client
47+
// implements the inject interface - e.g. inject.Client.
48+
// Depending on if a Runnable implements HARunnable interface, a Runnable can be run in either
49+
// HA mode (always running) or non-HA mode (managed by leader election if enabled).
4850
Add(Runnable) error
4951

5052
// SetFields will set any dependencies on an object for which the object has implemented the inject
@@ -172,6 +174,12 @@ func (r RunnableFunc) Start(s <-chan struct{}) error {
172174
return r(s)
173175
}
174176

177+
// HARunnable knows if a Runnable needs to be run in HA mode.
178+
type HARunnable interface {
179+
// IsHARunnable returns true if the Runnable (i.e. webhook server) need to be run in HA mode.
180+
IsHARunnable() bool
181+
}
182+
175183
// New returns a new Manager for creating Controllers.
176184
func New(config *rest.Config, options Options) (Manager, error) {
177185
// Initialize a rest.config if none was specified

pkg/manager/manager_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,11 @@ var _ = Describe("manger.Manager", func() {
284284
<-c2
285285
<-c3
286286
})
287+
288+
It("should return an error if any HA Components fail to Start", func() {
289+
// TODO(mengqiy): implement this after resolving https://github.com/kubernetes-sigs/controller-runtime/issues/429
290+
// Example: ListOptions
291+
})
287292
}
288293

289294
Context("with defaults", func() {

0 commit comments

Comments
 (0)