Stage 5 · Platform
Operators, CRDs & Controllers
Controller Pattern
Informers, work queues, idempotent reconciliation, finalizers, and status subresources.
Controller Pattern Overview
Controllers follow a reconcile loop: watch for events, compare desired state to actual state, and take action to converge them. This pattern is simple but powerful — it handles failures, retries, and concurrent updates gracefully.
func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
// 1. Fetch the resource
var myResource MyResource
if err := r.Get(ctx, req.NamespacedName, &myResource); err != nil {
return ctrl.Result{}, client.IgnoreNotFound(err)
}
// 2. Check if being deleted
if !myResource.DeletionTimestamp.IsZero() {
return r.handleDeletion(ctx, &myResource)
}
// 3. Compare desired vs actual state
desired := myResource.Spec
actual := r.getActualState(ctx, &myResource)
// 4. Take action to converge
if !reflect.DeepEqual(desired, actual) {
if err := r.reconcileState(ctx, &myResource, desired, actual); err != nil {
return ctrl.Result{}, err
}
}
// 5. Update status
myResource.Status.ObservedGeneration = myResource.Generation
if err := r.Status().Update(ctx, &myResource); err != nil {
return ctrl.Result{}, err
}
return ctrl.Result{RequeueAfter: 5 * time.Minute}, nil
}The Reconcile function is called whenever the resource changes. It fetches the resource, handles deletion, compares state, and updates status. RequeueAfter schedules the next reconciliation.
Informers
Informers watch the API server for resource changes. They maintain an in-memory cache of resources and deliver events (Added, Modified, Deleted) to handlers. Informers are efficient — they use watches, not polls.
Work Queues
Work queues decouple event reception from processing. Events are queued and processed at a controlled rate. Rate limiting prevents overwhelming the API server. Retries handle transient failures.
Idempotent Reconciliation
Reconciliation must be idempotent — applying the same action multiple times produces the same result. Use server-side apply or check current state before acting. This handles retries, duplicates, and concurrent updates safely.
Finalizers
Finalizers prevent resources from being deleted until cleanup is complete. Add a finalizer on creation, handle it during deletion, then remove it. This ensures external resources are cleaned up before the Kubernetes object is deleted.
Status Updates
Status updates reflect the controller's view of the resource. Update status after each reconciliation to report conditions, ready replicas, and observed generation. Use the status subresource to avoid conflicts with spec updates.
Use controller-runtime (from Kubebuilder) for building controllers. It handles informers, work queues, leader election, and health checks. Follow the Kubebuilder patterns for consistent, maintainable controllers.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.