A set of go libraries for building Kubernetes controllers with structured abstractions for managers, reconcilers, clients, caches, webhooks, and testing
npx @tessl/cli install tessl/golang-sigs-k8s-io--controller-runtime@0.22.0Controller-Runtime is a comprehensive Go library for building Kubernetes controllers and operators. It provides high-level abstractions over client-go and the Kubernetes API machinery, offering a structured framework for implementing custom controllers, webhooks, and operators with built-in support for caching, leader election, metrics, and testing.
go get sigs.k8s.io/controller-runtime@v0.22.4import (
"context"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"sigs.k8s.io/controller-runtime/pkg/builder"
"sigs.k8s.io/controller-runtime/pkg/log"
"k8s.io/apimachinery/pkg/runtime/schema"
)package main
import (
"context"
"fmt"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
)
// Define a reconciler
type PodReconciler struct {
client.Client
Scheme *runtime.Scheme
}
func (r *PodReconciler) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) {
// Fetch the Pod
var pod corev1.Pod
if err := r.Get(ctx, req.NamespacedName, &pod); err != nil {
return reconcile.Result{}, client.IgnoreNotFound(err)
}
// Implement reconciliation logic
fmt.Printf("Reconciling Pod: %s/%s\n", pod.Namespace, pod.Name)
return reconcile.Result{}, nil
}
func main() {
// Create a manager
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), manager.Options{})
if err != nil {
panic(err)
}
// Create and register a controller
if err := ctrl.NewControllerManagedBy(mgr).
For(&corev1.Pod{}).
Complete(&PodReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
}); err != nil {
panic(err)
}
// Start the manager
if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
panic(err)
}
}Controller-Runtime follows a modular architecture with several key components:
Manager: The central component that manages the lifecycle of controllers, caches, clients, and webhooks. It handles dependency injection and coordinates the startup/shutdown of all registered components.
Controller: Implements the control loop pattern, watching for events on Kubernetes resources and triggering reconciliation when changes occur.
Reconciler: Contains the business logic for bringing the actual state of resources into alignment with the desired state defined in their specifications.
Client: Provides a high-level interface for interacting with Kubernetes resources, abstracting away the complexity of REST operations and offering both cached reads and direct API writes.
Cache: An in-memory cache of Kubernetes resources with change notification capabilities through informers. Significantly reduces API server load by serving read requests from memory.
The core framework provides the foundational abstractions for building Kubernetes controllers, including manager lifecycle management, controller implementation, and reconciliation patterns.
// Manager is the central component for managing controllers
type Manager interface {
cluster.Cluster
Add(Runnable) error
Elected() <-chan struct{}
AddMetricsServerExtraHandler(path string, handler http.Handler) error
AddHealthzCheck(name string, check healthz.Checker) error
AddReadyzCheck(name string, check healthz.Checker) error
Start(ctx context.Context) error
GetWebhookServer() webhook.Server
GetLogger() logr.Logger
GetControllerOptions() config.Controller
}
// Create a new manager
func New(config *rest.Config, options Options) (Manager, error)// Controller implements a Kubernetes API by responding to events
type Controller interface {
reconcile.Reconciler
Watch(src source.Source) error
Start(ctx context.Context) error
GetLogger() logr.Logger
}
// Create a new controller
func New(name string, mgr manager.Manager, options Options) (Controller, error)// Reconciler is the core reconciliation interface
type Reconciler interface {
Reconcile(context.Context, Request) (Result, error)
}
// Request contains the information necessary to reconcile a Kubernetes object
type Request struct {
types.NamespacedName
}
// Result contains the result of a Reconciler invocation
type Result struct {
RequeueAfter time.Duration
}The client and cache subsystem provides efficient read and write operations against Kubernetes resources with intelligent caching, field indexing, and split-reader patterns for high-performance controllers.
// Client knows how to perform CRUD operations on Kubernetes objects
type Client interface {
Reader
Writer
StatusClient
SubResourceClientConstructor
Scheme() *runtime.Scheme
RESTMapper() meta.RESTMapper
GroupVersionKindFor(obj runtime.Object) (schema.GroupVersionKind, error)
IsObjectNamespaced(obj runtime.Object) (bool, error)
}
// Reader knows how to read and list Kubernetes objects
type Reader interface {
Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error
List(ctx context.Context, list ObjectList, opts ...ListOption) error
}
// Writer knows how to create, delete, update and patch Kubernetes objects
type Writer interface {
Create(ctx context.Context, obj Object, opts ...CreateOption) error
Delete(ctx context.Context, obj Object, opts ...DeleteOption) error
Update(ctx context.Context, obj Object, opts ...UpdateOption) error
Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error
Apply(ctx context.Context, obj runtime.ApplyConfiguration, opts ...ApplyOption) error
DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error
}// Cache knows how to load Kubernetes objects and fetch informers
type Cache interface {
client.Reader
Informers
}
// Informers knows how to create or fetch informers for different GVKs
type Informers interface {
GetInformer(ctx context.Context, obj client.Object, opts ...InformerGetOption) (Informer, error)
GetInformerForKind(ctx context.Context, gvk schema.GroupVersionKind, opts ...InformerGetOption) (Informer, error)
RemoveInformer(ctx context.Context, obj client.Object) error
Start(ctx context.Context) error
WaitForCacheSync(ctx context.Context) bool
client.FieldIndexer
}The builder package provides a fluent API for constructing controllers with minimal boilerplate code, making it easy to set up watches, event handlers, and predicates.
// Builder builds a Controller
type Builder struct {
// Has unexported fields
}
// ControllerManagedBy returns a new controller builder that will be started by the provided Manager
func ControllerManagedBy(m manager.Manager) *Builder
// For defines the type of Object being reconciled
func (blder *Builder) For(object client.Object, opts ...ForOption) *Builder
// Owns defines types of Objects being generated by the controller
func (blder *Builder) Owns(object client.Object, opts ...OwnsOption) *Builder
// Watches watches arbitrary objects and enqueues reconcile requests
func (blder *Builder) Watches(
object client.Object,
eventHandler handler.EventHandler,
opts ...WatchesOption,
) *Builder
// WithEventFilter sets predicates to filter events before enqueuing
func (blder *Builder) WithEventFilter(p predicate.Predicate) *Builder
// Complete builds the controller
func (blder *Builder) Complete(r reconcile.Reconciler) errorThe event handling subsystem provides flexible event routing with sources, handlers, and predicates for fine-grained control over which events trigger reconciliation.
// EventHandler enqueues reconcile.Requests in response to events
type EventHandler interface {
Create(context.Context, event.CreateEvent, workqueue.RateLimitingInterface)
Update(context.Context, event.UpdateEvent, workqueue.RateLimitingInterface)
Delete(context.Context, event.DeleteEvent, workqueue.RateLimitingInterface)
Generic(context.Context, event.GenericEvent, workqueue.RateLimitingInterface)
}
// Predicate filters events before they are provided to EventHandlers
type Predicate interface {
Create(event.CreateEvent) bool
Delete(event.DeleteEvent) bool
Update(event.UpdateEvent) bool
Generic(event.GenericEvent) bool
}
// Source is a source of events for a Controller
type Source interface {
Start(context.Context, workqueue.RateLimitingInterface) error
}The webhook framework provides comprehensive support for implementing admission webhooks (validating and mutating), authentication webhooks, and conversion webhooks with automatic server management.
// Server manages webhook registration and serving
type Server interface {
NeedLeaderElection() bool
Register(path string, hook http.Handler)
Start(ctx context.Context) error
StartedChecker() healthz.Checker
WebhookMux() *http.ServeMux
}
// Handler processes admission requests
type Handler interface {
Handle(context.Context, Request) Response
}
// CustomValidator validates create, update, and delete operations
type CustomValidator interface {
ValidateCreate(ctx context.Context, obj runtime.Object) (warnings Warnings, err error)
ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (warnings Warnings, err error)
ValidateDelete(ctx context.Context, obj runtime.Object) (warnings Warnings, err error)
}
// CustomDefaulter sets defaults on objects
type CustomDefaulter interface {
Default(ctx context.Context, obj runtime.Object) error
}Comprehensive testing utilities including envtest for running integration tests against a real API server, fake clients for unit testing, and utilities for testing with Gomega matchers.
// Environment provides a test control plane with etcd and kube-apiserver
type Environment struct {
ControlPlane controlplane.ControlPlane
Scheme *runtime.Scheme
Config *rest.Config
CRDInstallOptions CRDInstallOptions
WebhookInstallOptions WebhookInstallOptions
UseExistingCluster *bool
ControlPlaneStartTimeout time.Duration
ControlPlaneStopTimeout time.Duration
AttachControlPlaneOutput bool
}
func (te *Environment) Start() (*rest.Config, error)
func (te *Environment) Stop() error// ClientBuilder builds fake clients for testing
type ClientBuilder struct {
// Has unexported fields
}
func NewClientBuilder() *ClientBuilder
func (f *ClientBuilder) WithObjects(initObjs ...client.Object) *ClientBuilder
func (f *ClientBuilder) WithScheme(scheme *runtime.Scheme) *ClientBuilder
func (f *ClientBuilder) Build() client.WithWatchSupporting services include structured logging with logr, Prometheus metrics integration, health checks, and leader election for high availability deployments.
// Logging functions
func SetLogger(l logr.Logger)
func FromContext(ctx context.Context, keysAndValues ...interface{}) logr.Logger
func IntoContext(ctx context.Context, log logr.Logger) context.Context// Metrics registry
var Registry RegistererGatherer = prometheus.NewRegistry()
// Health check types
type Checker func(req *http.Request) error
var Ping Checker = func(_ *http.Request) error { return nil }// Leader election options
type Options struct {
LeaderElection bool
LeaderElectionResourceLock string
LeaderElectionNamespace string
LeaderElectionID string
RenewDeadline time.Duration
LeaderLabels map[string]string
}Utility packages for common operations including finalizer management, scheme building, configuration, and certificate watching for webhook servers.
// Finalizer operations
func AddFinalizer(o client.Object, finalizer string) (finalizersUpdated bool)
func RemoveFinalizer(o client.Object, finalizer string) (finalizersUpdated bool)
func ContainsFinalizer(o client.Object, finalizer string) bool// Owner reference management
func SetControllerReference(owner, controlled metav1.Object, scheme *runtime.Scheme, opts ...OwnerReferenceOption) error
func SetOwnerReference(owner, object metav1.Object, scheme *runtime.Scheme, opts ...OwnerReferenceOption) error// Scheme building
type Builder struct {
GroupVersion schema.GroupVersion
runtime.SchemeBuilder
}
func (bld *Builder) Register(object ...runtime.Object) *Builder
func (bld *Builder) Build() (*runtime.Scheme, error)