@@ -67,6 +67,7 @@ type controllerManager struct {
67
67
// leaderElectionRunnables is the set of Controllers that the controllerManager injects deps into and Starts.
68
68
// These Runnables are managed by lead election.
69
69
leaderElectionRunnables []Runnable
70
+
70
71
// nonLeaderElectionRunnables is the set of webhook servers that the controllerManager injects deps into and Starts.
71
72
// These Runnables will not be blocked by lead election.
72
73
nonLeaderElectionRunnables []Runnable
@@ -577,10 +578,27 @@ func (cm *controllerManager) startNonLeaderElectionRunnables() {
577
578
cm .mu .Lock ()
578
579
defer cm .mu .Unlock ()
579
580
581
+ // First start any webhook servers, which includes conversion, validation, and defaulting
582
+ // webhooks that are registered.
583
+ //
584
+ // WARNING: Webhooks MUST start before any cache is populated, otherwise there is a race condition
585
+ // between conversion webhooks and the cache sync (usually initial list) which causes the webhooks
586
+ // to never start because no cache can be populated.
587
+ for _ , c := range cm .nonLeaderElectionRunnables {
588
+ if _ , ok := c .(* webhook.Server ); ok {
589
+ cm .startRunnable (c )
590
+ }
591
+ }
592
+
593
+ // Start and wait for caches.
580
594
cm .waitForCache (cm .internalCtx )
581
595
582
596
// Start the non-leaderelection Runnables after the cache has synced
583
597
for _ , c := range cm .nonLeaderElectionRunnables {
598
+ if _ , ok := c .(* webhook.Server ); ok {
599
+ continue
600
+ }
601
+
584
602
// Controllers block, but we want to return an error if any have an error starting.
585
603
// Write any Start errors to a channel so we can return them
586
604
cm .startRunnable (c )
0 commit comments