Skip to content
This repository was archived by the owner on Dec 2, 2025. It is now read-only.

Commit 429bbe8

Browse files
committed
Add configurable concurrent reconciliation to controllers
The controller-runtime defaults MaxConcurrentReconciles to 1, which creates a bottleneck when multiple BMC operations need to be processed simultaneously. This is particularly noticeable during cluster provisioning when many nodes are being set up in parallel. This change adds a CLI flag (--max-concurrent-reconciles) and corresponding environment variable (RUFIO_MAX_CONCURRENT_RECONCILES) to configure the number of concurrent reconciliations across all controllers. Signed-off-by: Rahul Ganesh <rahulgab@amazon.com>
1 parent 61d8853 commit 429bbe8

File tree

4 files changed

+20
-11
lines changed

4 files changed

+20
-11
lines changed

controller/job.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
utilerrors "k8s.io/apimachinery/pkg/util/errors"
2727
ctrl "sigs.k8s.io/controller-runtime"
2828
"sigs.k8s.io/controller-runtime/pkg/client"
29+
ctrlcontroller "sigs.k8s.io/controller-runtime/pkg/controller"
2930
"sigs.k8s.io/controller-runtime/pkg/handler"
3031

3132
"github.com/tinkerbell/rufio/api/v1alpha1"
@@ -221,7 +222,7 @@ func (r *JobReconciler) patchStatus(ctx context.Context, job *v1alpha1.Job, patc
221222
}
222223

223224
// SetupWithManager sets up the controller with the Manager.
224-
func (r *JobReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager) error {
225+
func (r *JobReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager, opts ctrlcontroller.Options) error {
225226
if err := mgr.GetFieldIndexer().IndexField(
226227
ctx,
227228
&v1alpha1.Task{},
@@ -233,6 +234,7 @@ func (r *JobReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager)
233234

234235
return ctrl.NewControllerManagedBy(mgr).
235236
For(&v1alpha1.Job{}).
237+
WithOptions(opts).
236238
Watches(
237239
&v1alpha1.Task{},
238240
handler.EnqueueRequestForOwner(

controller/machine.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ import (
2929
"k8s.io/apimachinery/pkg/types"
3030
utilerrors "k8s.io/apimachinery/pkg/util/errors"
3131
"k8s.io/client-go/tools/record"
32+
ctrlcontroller "sigs.k8s.io/controller-runtime/pkg/controller"
33+
3234
ctrl "sigs.k8s.io/controller-runtime"
3335
"sigs.k8s.io/controller-runtime/pkg/client"
3436

@@ -210,8 +212,9 @@ func retrieveHMACSecrets(ctx context.Context, c client.Client, hmacSecrets v1alp
210212
}
211213

212214
// SetupWithManager sets up the controller with the Manager.
213-
func (r *MachineReconciler) SetupWithManager(mgr ctrl.Manager) error {
215+
func (r *MachineReconciler) SetupWithManager(mgr ctrl.Manager, opts ctrlcontroller.Options) error {
214216
return ctrl.NewControllerManagedBy(mgr).
215217
For(&v1alpha1.Machine{}).
218+
WithOptions(opts).
216219
Complete(r)
217220
}

controller/task.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
utilerrors "k8s.io/apimachinery/pkg/util/errors"
2626
ctrl "sigs.k8s.io/controller-runtime"
2727
"sigs.k8s.io/controller-runtime/pkg/client"
28+
ctrlcontroller "sigs.k8s.io/controller-runtime/pkg/controller"
2829

2930
"github.com/tinkerbell/rufio/api/v1alpha1"
3031
)
@@ -274,8 +275,9 @@ func (r *TaskReconciler) patchStatus(ctx context.Context, task *v1alpha1.Task, p
274275
}
275276

276277
// SetupWithManager sets up the controller with the Manager.
277-
func (r *TaskReconciler) SetupWithManager(mgr ctrl.Manager) error {
278+
func (r *TaskReconciler) SetupWithManager(mgr ctrl.Manager, opts ctrlcontroller.Options) error {
278279
return ctrl.NewControllerManagedBy(mgr).
279280
For(&v1alpha1.Task{}).
281+
WithOptions(opts).
280282
Complete(r)
281283
}

main.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,16 @@ import (
3333
"github.com/peterbourgon/ff/v3"
3434
"github.com/peterbourgon/ff/v3/ffcli"
3535
"github.com/rs/zerolog"
36+
"github.com/tinkerbell/rufio/api/v1alpha1"
37+
"github.com/tinkerbell/rufio/controller"
3638
"k8s.io/apimachinery/pkg/runtime"
3739
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
3840
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
3941
ctrl "sigs.k8s.io/controller-runtime"
4042
"sigs.k8s.io/controller-runtime/pkg/cache"
43+
ctrlcontroller "sigs.k8s.io/controller-runtime/pkg/controller"
4144
"sigs.k8s.io/controller-runtime/pkg/healthz"
4245
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
43-
44-
"github.com/tinkerbell/rufio/api/v1alpha1"
45-
"github.com/tinkerbell/rufio/controller"
4646
//+kubebuilder:scaffold:imports
4747
)
4848

@@ -86,6 +86,7 @@ func main() {
8686
var kubeconfig string
8787
var kubeNamespace string
8888
var bmcConnectTimeout time.Duration
89+
var maxConcurrentReconciles int
8990
fs := flag.NewFlagSet(appName, flag.ExitOnError)
9091
fs.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.")
9192
fs.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
@@ -96,6 +97,7 @@ func main() {
9697
fs.StringVar(&kubeconfig, "kubeconfig", "", "Absolute path to the kubeconfig file.")
9798
fs.StringVar(&kubeNamespace, "kube-namespace", "", "Namespace that the controller watches to reconcile objects.")
9899
fs.DurationVar(&bmcConnectTimeout, "bmc-connect-timeout", 60*time.Second, "Timeout for establishing a connection to BMCs.")
100+
fs.IntVar(&maxConcurrentReconciles, "max-concurrent-reconciles", 1, "Maximum number of concurrent reconciles per controller.")
99101
cli := &ffcli.Command{
100102
Name: appName,
101103
FlagSet: fs,
@@ -144,7 +146,7 @@ func main() {
144146
bmcClientFactory := controller.NewClientFunc(bmcConnectTimeout)
145147

146148
// Setup controller reconcilers
147-
setupReconcilers(ctx, mgr, bmcClientFactory)
149+
setupReconcilers(ctx, mgr, bmcClientFactory, maxConcurrentReconciles)
148150

149151
//+kubebuilder:scaffold:builder
150152

@@ -175,20 +177,20 @@ func newClientConfig(kubeAPIServer, kubeconfig string) clientcmd.ClientConfig {
175177
}
176178

177179
// setupReconcilers initializes the controllers with the Manager.
178-
func setupReconcilers(ctx context.Context, mgr ctrl.Manager, bmcClientFactory controller.ClientFunc) {
180+
func setupReconcilers(ctx context.Context, mgr ctrl.Manager, bmcClientFactory controller.ClientFunc, maxConcurrentReconciles int) {
179181
err := (controller.NewMachineReconciler(
180182
mgr.GetClient(),
181183
mgr.GetEventRecorderFor("machine-controller"),
182184
bmcClientFactory,
183-
)).SetupWithManager(mgr)
185+
)).SetupWithManager(mgr, ctrlcontroller.Options{MaxConcurrentReconciles: maxConcurrentReconciles})
184186
if err != nil {
185187
setupLog.Error(err, "unable to create controller", "controller", "Machine")
186188
os.Exit(1)
187189
}
188190

189191
err = (controller.NewJobReconciler(
190192
mgr.GetClient(),
191-
)).SetupWithManager(ctx, mgr)
193+
)).SetupWithManager(ctx, mgr, ctrlcontroller.Options{MaxConcurrentReconciles: maxConcurrentReconciles})
192194
if err != nil {
193195
setupLog.Error(err, "unable to create controller", "controller", "Job")
194196
os.Exit(1)
@@ -197,7 +199,7 @@ func setupReconcilers(ctx context.Context, mgr ctrl.Manager, bmcClientFactory co
197199
err = (controller.NewTaskReconciler(
198200
mgr.GetClient(),
199201
bmcClientFactory,
200-
)).SetupWithManager(mgr)
202+
)).SetupWithManager(mgr, ctrlcontroller.Options{MaxConcurrentReconciles: maxConcurrentReconciles})
201203
if err != nil {
202204
setupLog.Error(err, "unable to create controller", "controller", "Task")
203205
os.Exit(1)

0 commit comments

Comments
 (0)