Operator Pattern: Kubernetes/Openshift
In this post, we will understand the Operator Pattern, Kubernetes internals, and essentials concepts for building an operator.
In the real world, we can define Operators: as a person who operates on something (machine, equipment, process). Let’s say it works on a given task “X”. Kubernetes Operator also works to follow the same principles.
We can classify any operator qualities into three categories:
They observe the X work, analyze the state of X, and finally act based on the current state of X to reach the desired state. Which will make the operators task completed, once we attain the desired state.
Similar work/tasks are performed by Kubernetes Operators. It helps us to extend the Kubernetes API to allow custom functionality or behavior based on the needs of the consumer.
We can categories building cloud-native applications in two categories:
- Containerize Application: Running an application container within the Kubernetes control plane as a Pod. Performing some kind of Request/Response.
- Operator Pattern: This pattern allows you to capitalize on Kubernetes infra and uses for our benefits.
In the above Figure 1, the Operator acts like having an understanding of Kubernetes internals like Events and API. It allows us to execute custom logic and query Kubernetes API for modifying the state of resources. Before going deep into Operators we can build our understanding of the Kubernetes internals:
It implements multiple controllers in a single process that runs in the control plane as a replicated set of processes. It consists of controllers like Node Controller, Route Controller, Service Controller, Authorization Controller, etc. We will see in detail how the controller works internally in the Operator pattern.
API Server: Schema
As shown in Figure 3, we can see each resource defined within the Kubernetes Control Plane is defined as an API end-point. When you are using the kubectl CLI tool. You are interacting with the Kube API like
kubectl <verb> <resource>
For extending the Schema, we can define a Custom Resource Definition type and create instances (CR) to perform the desired task using a custom controller.
In the above figure, we are creating an instance(“example-job”) of type: Job. This is managed by Job controller runtime which handles the creation of container which executes the defined arguments. We got an understanding of the core internals. Now we can explore the pattern
Operator = Customer Resource Definition + Custom Controller
In the case of Kubernetes Operator, the same qualities are followed
- Observe: Events
- Analyze: Current Vs Desired State
- Act: Reconciler Loop
We can understand each in-depth:
- Controller: Register the Custom Resource Definition and adds it to the Kubernetes API Schema, exposes a new API end-point for the CRD, added watchers for the namespace to observe, runs a process/loop i.e control loop for acting based on the desired change.
- Watchers: Allows to observe the events for specific resources type.
- Reconciler: Any modification to the CR is handled by the reconciliation loop. Requeue after conflict/error with an interval defined by the re-sync period.
Classification based on deployment type
- Namespace scoped Operator
- Cluster scoped Operator
For understanding read: namespace vs cluster scope operator
State Modification: Current Vs Desired
We have a customer resource for Kind: Memcached (Custom Resource). With a specification field size (defined as 3). In the case of any modification to the customer resource. For eg: size 3 to 4.
An event will be triggered which can be watched by configuring a Watcher(Observe) for the resource object: Memcached within the Custom Controller. The reconciliation loop consists of custom logic defined by us. which can be used to compares the current (size: 3) vs desired (size: 4) & make the desired action.
Example Operator Workflow
- Defines a namespace(namespace-scoped) for our controller
- Creates the CRD: ToDo.
- The controller analyzes the CRD and adds it to the Kubernetes API Schema, exposes a new API end-point for the CRD, added watchers for kind CRD type.
- Now our controller is in the running state. It watches the namespace for any changes.
- Creating an instance of the CRD, by creating a Custome Resource object (CR) [Manual step]
- When a CR object is created. it triggers an event that gives control to the Reconciler loop.
- Reconcile reads that state of the cluster for a Custom object and makes changes based on the desired state.
- In this case, it will create a Pod for the desired ToDo resource or any custom logic we intend for this operator
In conclusion, the above workflow is applicable to any operator. Except for the last point where creating a pod is a custom logic defined in the reconciler loop. Operator-Framework can be used to generate an operator and which provides high-level APIs, useful abstractions, and project scaffolding. Currently only support: Helm, Ansible & Go lang based operators. You can design operators in any preferred language using the Kubernetes client libraries with a combination of the helm charts. The following links will help to get started with operators.
Docs can be found on the Operator SDK website. This project is a component of the Operator Framework, an open source…
The Operator Framework ( intro blog post) is an open source toolkit to manage Kubernetes native applications, called…
Running Keycloak as Openshift Operator
In this post, we will see how to utilize the Kubernetes/Openshift Operator pattern to run the keycloak-operator in…
Thank you for reading this article. If you like this post, please give a Cheer!!! Follow the Collection: operators for learning more…
Happy Coding ❤