What are Kubernetes Controllers?
In Kubernetes, a controller is a control loop that watches the state of the cluster, then makes or requests changes that move the current state toward the desired state. Controllers are the fundamental building blocks that manage the desired state of your applications and cluster resources. They are continuously running processes that observe the current state of objects and reconcile it with the desired state specified in their configuration.
The Kubernetes API server is the central hub for all communication. Controllers interact with the API server to:
- Watch for changes to specific resource types (e.g., Deployments, Pods, Services).
- Observe the current state of these resources.
- Compare the current state with the desired state.
- Act to bring the current state in line with the desired state.
How Controllers Work: The Control Loop
The operational model of a controller is often referred to as a control loop. This loop consists of three main phases:
- Observe: The controller watches the Kubernetes API server for changes to the objects it manages.
- Analyze: It compares the current state of these objects with the desired state defined by the user or other controllers.
- Act: If there's a discrepancy, the controller takes action to correct it. This action typically involves creating, updating, or deleting other Kubernetes objects.
Diagram illustrating the observe-analyze-act control loop.
Key Types of Kubernetes Controllers
Kubernetes comes with several built-in controllers, each responsible for managing specific resources:
- ReplicationController / ReplicaSet Controller
- Ensures that a specified number of pod replicas are running at any given time. If a pod dies, the controller creates a new one. If too many are running, it terminates them. ReplicaSets are the successor to ReplicationControllers, offering more advanced features like declarative updates.
- Deployment Controller
- Manages Deployments, which provide declarative updates to Pods and ReplicaSets. Deployments enable described application state changes to be sent to the cluster. It manages rolling updates and rollbacks.
- StatefulSet Controller
- Manages StatefulSets, which are used for stateful applications that require stable network identifiers, stable persistent storage, and ordered, graceful deployment and scaling.
- DaemonSet Controller
- Ensures that all (or some) Nodes run a copy of a Pod. DaemonSets are useful for cluster-wide services like log collection or network monitoring.
- Job Controller
- Creates one or more Pods and ensures that a specified number of them successfully terminate. Jobs are suitable for tasks that run to completion, like batch processing or database migrations.
- CronJob Controller
- Manages CronJobs, which create Jobs on a repeating schedule. Similar to cron jobs in Unix-like systems.
- Namespace Controller
- Manages the lifecycle of Kubernetes Namespaces, which provide a mechanism for isolating groups of resources within a single cluster.
- Service Controller
- Manages Services, which provide a stable IP address and DNS name for a set of Pods. It ensures that network endpoints for a Service are updated as Pods change.
Custom Controllers
Beyond the built-in controllers, Kubernetes' extensibility allows for the creation of custom controllers. This is achieved through the Operator Pattern. Operators extend the Kubernetes API with custom resources (CRDs - Custom Resource Definitions) and package the knowledge of how to run, manage, and scale those applications into controller code.
This pattern is powerful for managing complex stateful applications like databases, message queues, or distributed systems, automating tasks that would typically require manual intervention.
Example: A Simple Deployment Controller Workflow
Let's consider how a Deployment controller might work:
- User defines a Deployment: You create a YAML file specifying your desired application state, including the container image, number of replicas, and update strategy.
- API Server receives the Deployment: Kubernetes API server stores this desired state.
- Deployment Controller observes: The Deployment controller notices the new Deployment object.
- Creates ReplicaSet: The Deployment controller creates a ReplicaSet object based on the Deployment's spec.
- ReplicaSet Controller observes: The ReplicaSet controller notices its new ReplicaSet object.
- Creates Pods: The ReplicaSet controller creates the specified number of Pods as defined in the ReplicaSet.
- Kubelet on Nodes: Each node's Kubelet sees the Pods scheduled for it and starts the containers.
- Reconciliation: If a Pod fails, the ReplicaSet controller will notice the discrepancy in the desired number of replicas and create a new Pod to compensate. If you update the Deployment's image, the Deployment controller will manage the process of creating a new ReplicaSet and gradually rolling out new Pods while terminating old ones.
Illustrative Code Snippet (Conceptual)
While the actual controller code is complex and written in Go, a simplified conceptual representation of the reconciliation loop might look like this:
// Simplified conceptual Go code for a controller's reconcile loop
func (r *MyController) Reconcile(request reconcile.Request) (reconcile.Result, error) {
// Fetch the desired object (e.g., a custom resource)
instance := &myv1alpha1.MyResource{}
err := r.client.Get(context.TODO(), request.NamespacedName, instance)
if err != nil {
if errors.IsNotFound(err) {
// Object not found, could have been deleted
return reconcile.Result{}, nil
}
// Error reading the object - requeue the request
return reconcile.Result{}, err
}
// Check the current state of dependent resources (e.g., Pods, Services)
// ... logic to fetch and compare current state ...
// If current state does not match desired state
if !statesMatch(instance, currentState) {
// Create, update, or delete dependent resources
// ... reconciliation logic ...
log.Printf("Reconciling %s/%s", instance.Namespace, instance.Name)
// Optionally return a requeue request with a delay
return reconcile.Result{Requeue: true, RequeueAfter: time.Second * 5}, nil
}
// State is in sync
return reconcile.Result{}, nil
}
Conclusion
Kubernetes controllers are the silent engines that drive the platform's automation capabilities. By constantly observing and reconciling the state of cluster resources, they ensure that your applications and infrastructure remain in their desired configuration, providing resilience, scalability, and manageability. Understanding how these control loops work is crucial for effectively operating and extending Kubernetes.
Further Reading: