Sign In

Curriculum 31: Extending Kubectl

Writing Controllers

30 min · 50 XP

Writing Controllers

A Kubernetes controller is a control loop that watches resources and takes action to move the current state toward the desired state. Controllers are the backbone of Kubernetes itself and the standard way to extend platform behavior.

The Controller Pattern

Every controller follows the same pattern: observe, diff, act.

// Simplified controller loop
for {
    desired := getDesiredState()   // From the resource spec
    current := getCurrentState()   // From the cluster
    if desired != current {
        reconcile(desired, current) // Make changes
    }
}

The Reconciliation Loop

Controllers receive events (add, update, delete) and reconcile the resource. The reconcile function is idempotent and convergent:

func (r *MyAppReconciler) Reconcile(ctx context.Context,
    req ctrl.Request) (ctrl.Result, error) {

    // Fetch the custom resource
    var myapp myappv1.MyApp
    if err := r.Get(ctx, req.NamespacedName, &myapp); err != nil {
        return ctrl.Result{}, client.IgnoreNotFound(err)
    }

    // Check if the deployment exists
    var deployment appsv1.Deployment
    err := r.Get(ctx, req.NamespacedName, &deployment)
    if errors.IsNotFound(err) {
        // Create the deployment
        dep := r.constructDeployment(&myapp)
        return ctrl.Result{}, r.Create(ctx, dep)
    }

    // Update if needed
    return ctrl.Result{}, r.Update(ctx, &deployment)
}

Kubebuilder

Kubebuilder scaffolds controller projects with best practices built in:

# Initialize a new project
kubebuilder init --domain example.com --repo github.com/org/mycontroller

# Create an API (resource + controller)
kubebuilder create api --group apps --version v1 --kind MyApp

# Generate manifests (CRDs, RBAC, etc.)
make manifests

# Run the controller locally
make run

# Build and deploy to the cluster
make docker-build docker-push IMG=myregistry/controller:v1
make deploy IMG=myregistry/controller:v1

Testing Controllers

# Kubebuilder generates test scaffolding
make test

# Check controller logs in the cluster
kubectl logs -n mycontroller-system deployment/mycontroller-manager

Controllers should handle errors gracefully by returning requeue results, allowing Kubernetes to retry with exponential backoff.