Operator

overview

Per the Kubernetes glossary, a controller is an application that implements a control-loop that observes the shared state of the cluster through the API server, evaluates the changes needed to move the current state toward the desired state and finally applies the changes to reconcile the resources to the desired state.

control-loop

This pattern is the foundation of every Controllers shipped by default by Kubernetes but can also be used by Operators that are controllers that encode domain specific knowledge and extends the Kubernetes API to create, configure and manage instances of complex applications on behalf of Kubernetes users.

With the Camel K Operator we have moved this pattern to the next level as it goes beyond the tasks to install and maintain applications but materializes them according to the integration logic expressed through the Camel DSL.

The Camel K Operator defines a number of new Kubernetes API through the Custom Resource (CR) extension mechanism:

All the api conform to the Kubernetes api conventions.

To manage the interaction with them, a simple control loop was not enough and we ended up with a sort of “Hierarchical Operator Pattern” where the reconcile phase may trigger other controllers and supervises them.

control-loop

State Machine

With the exception of the CamelCatalog, each CR has a dedicated state machine in charge to orchestrate the transition to the phases each CR needs to go through to bring integrations to the desired state.

State Machine

Each state of the CR is handled by a dedicated handler, named Action, defined as follow:

type Action interface {
	CanHandle(cr *v1.CR) bool (1)
	Handle(ctx context.Context, cr *v1.CR) (*v1.CR, error) (2)
}
1 Determine if the action can handle the CR as an example by looking at the phase of the CR which is store as part of the status sub resource.
2 Implement the action and return a non nil instance to signal to the controller that the CR needs to be updated with the new one, instead, if the method returns a nil instance, then nothing will happen and unless the CR changes outside the control of the operator, the same action will be invoked on the next iteration. This is useful when a CR needs to delegate some work to a different controller so the CR won’t be moved to the next stage till the sub operation has completed.

Since the go language does not yet support generics, there is an Action definition per CR, The full list of definitions can be found in the controller package