- Controllers are control loops that watch the state of your cluster & update the actual state of the cluster, examples below are core controllers managed by the Kubernetes controller manager in the control plane:
- Node controller: Responsible for noticing and responding when nodes go down.
- Job controller: Watches for Job objects that represent one-off tasks, then creates Pods to run those tasks to completion.
- ServiceAccount controller: Create default ServiceAccounts for new namespaces.
- Resources: are endpoints in the Kubernetes API.
- Custom resources: are extensions of the Kubernetes API that is not necessarily available in the default Kubernetes installation.
- Operators are application-specific controllers.
An operator is a type of controller that extends Kubernetes’ functionality to manage custom resources (CRDs - Custom Resource Definitions) specific to a particular application or workload. Unlike built-in controllers in Kubernetes, which handle standard resources like Pods, Deployments, and Services, operators are tailored to manage higher-level abstractions created by users for their applications.
While Golang is the dominant language in the Kubernetes ecosystem, there are other popular operators and frameworks for building operators in languages other than Go:
- Kopf : is a Python framework for building Kubernetes operators.
- Java Operator SDK: The Java Operator SDK is a framework for building Kubernetes operators using the Java programming language.
- kube-rs: is a Rust library for interacting with Kubernetes. It provides bindings to the Kubernetes API and can be used to build custom operators in Rust.
- dotnet-operator-sdk: The dotnet Kubernetes Operator SDK.
In this post, we will walk through the process of building a simple operator using Kopf. The operator we’ll create is an alert operator that monitors the states of pods and generates alerts for pods that are not running. We will also include log trails to assist application developers in debugging.
Please note that this tutorial focuses on the core functionality of the operator. Although it can be extended to integrate with Slack webhooks to send alerts to specific channels, we will keep the tutorial simple and solely focus on the basic implementation.
By the end of this tutorial, you will have a solid understanding of how to build a basic operator using Kopf and leverage its capabilities to enhance your Kubernetes-based applications. Let’s get started!
minikube start --cpus 4 --memory 4096
Let us define a CRD (custom resource definition) for our alerting object:
kubectl apply -f alert.yaml
The yaml above is a CustomResourceDefinition (CRD) resource in Kubernetes. Let’s break down the different sections:
apiextensions.k8s.io/v1specifies the API version of the CustomResourceDefinition resource.
- metadata: Contains metadata information about the CustomResourceDefinition resource.
- spec: Defines the specifications for the CustomResourceDefinition.
Namespaced, Specifies that the custom resource defined by this CRD will be namespaced, meaning it will be limited to a specific namespace.
kopf.dev: Specifies the group to which this custom resource belongs.
OrchestrSpecifies the singular name of the custom resource. In this case, the singular form is
- plural: orchestrs: Specifies the plural name of the custom resource. In this case, the plural form is
- openAPIV3Schema: Specifies the OpenAPI v3 schema for the custom resource.
x-kubernetes-preserve-unknown-fields: Indicates that any unknown fields encountered in the custom resource should be preserved when reading or writing the resource.
kubectl apply -f obj.yaml
Get a list of the existing objects of this kind with one of the commands:
kubectl get Orchestr
The following 3 core cause-handlers are available on Kopf, they keep track of the following
- When are object is created
- When an object is deleted
- When an object is updated
For this post, we will just focus on the
kopf.on.create is a decorator or function provided by the Kopf framework for defining handlers that are triggered when a new resource of a specific kind is created in Kubernetes.
The code you provided is a Python script that uses the Kopf framework to build a Kubernetes operator. Let’s go through the code and explain its functionality:
- The script starts by importing necessary modules:
kubernetesfor interacting with the Kubernetes cluster
kopffor building the operator
ApiExceptionfrom kubernetes.client.rest for handling API exceptions.
The @kopf.on.create('orchestrs')decorator indicates that the following function is a handler for the creation of custom resources of kind
'orchestrs'. When a new resource of this kind is created, the create_fn function will be triggered.
- Inside the
create_fnfunction, it retrieves the value of the
alerts.checkRunningPodsfield from the custom resource’s spec. If this field is not set, it raises a kopf.PermanentError with an error message indicating that an alert must be set.
check_pod_statusfunction is called to check the status of all pods in the cluster. It retrieves the list of pods using the Kubernetes client and iterates over each pod to check if its status is not “Running”. If a pod is found with a status other than “Running”, it collects information about the pod, such as its name, namespace, status, and any issues related to its containers. These problematic pods are stored in the problematic_pods list.
get_pod_logsfunction retrieves the logs for a specific pod in a given namespace. It uses the Kubernetes client to read the logs for the specified pod. If an ApiException occurs while retrieving the logs, it raises an exception with an appropriate error message.
docker image build -t lindaindicina/alert-operator:latest .
Operators often need RBAC (Role-Based Access Control) to perform various tasks within a Kubernetes cluster.
kubectl apply -f rbac.yaml
kubectl get pods
The example discussed in this article serves as a simple introduction to using Kopf. It aims to provide beginners with valuable insights and a starting point for utilizing Kopf in their Kubernetes projects.
Hello 👋, If you enjoyed this article, please consider subscribing to my email newsletter. Subscribe 📭