Operator-SDK: Write a generic controller for an existing object

Operator-SDK controller

2 min read | by Jordi Prats

With operator-sdk, it really makes it easy to create new CRD definitions and create the template to write the reconcile loop for it. But if we want to be able to handle changes on objects that are already present on the Kubernetes cluster (not a custom resources) we can create the Reconciler from scratch.

As an example, we are going to create a Pod reconciler, to do so we just need to create a new file in the controllers folder with the following contents:

package controllers

import (
  "context"

  "github.com/go-logr/logr"
  log "github.com/sirupsen/logrus"
  corev1 "k8s.io/api/core/v1"
  "k8s.io/apimachinery/pkg/runtime"
  ctrl "sigs.k8s.io/controller-runtime"
  "sigs.k8s.io/controller-runtime/pkg/client"
)

// PodReconciler reconciles Namespace objects
type PodReconciler struct {
  client.Client
  Log    logr.Logger
  Scheme *runtime.Scheme
}

func (r *PodReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
  log.Infof("Reconciling Pod %s in namespace %s", req.Name, req.NamespacedName)

  // logic here

  return ctrl.Result{}, nil
}

// SetupWithManager sets up the controller with the Manager.
func (r *PodReconciler) SetupWithManager(mgr ctrl.Manager) error {
  return ctrl.NewControllerManagedBy(mgr).
    For(&corev1.Pod{}).
    Complete(r)
}

And then register the controller in the main.go file with all the other controllers. We can look for //+kubebuilder:scaffold:builder to find it:

  if err = (&controllers.PodReconciler{
    Client: mgr.GetClient(),
    Log:    ctrl.Log.WithName("controllers").WithName("Pod"),
  }).SetupWithManager(mgr); err != nil {
    setupLog.Error(err, "unable to create controller", "controller", "PodReconciler")
    os.Exit(1)
  }

  if err = (&controllers.OneController{
    Client: mgr.GetClient(),
    Scheme: mgr.GetScheme(),
  }).SetupWithManager(mgr); err != nil {
    setupLog.Error(err, "unable to create controller", "controller", "OneController")
    os.Exit(1)
  }
  if err = (&controllers.AnotherController{
    Client: mgr.GetClient(),
    Scheme: mgr.GetScheme(),
  }).SetupWithManager(mgr); err != nil {
    setupLog.Error(err, "unable to create controller", "controller", "AnotherController")
    os.Exit(1)
  }
  //+kubebuilder:scaffold:builder

We can add whatever logic we need by adding the relevant code into the PodReconciler.Reconcile() function.


Posted on 22/12/2023