Build your own Python Kubernetes Operator

Yes, you read it right – build a Kubernetess operator in Python! Often reactions follow like, "But doesn't it have to be in Golang?" Fortunately, that's not necessary if you have a preference for Python. So, let us guide you through a small how-to, allowing you to build your own operator. 

Python Kubernetes Operator

Why use an operator?

An operator is like a smart assistant that understands the complexity of your Kubernetes cluster and can automate specific tasks. It enables you to create custom automation for your (custom) applications, minimizing manual intervention.

The power of an operator lies in its ability to autonomously perform tasks such as scalability, maintenance, and self-healing. This boosts efficiency and minimises errors.

While some tasks can be performed with deployments, etc., if you're looking for additional logic, an operator is an excellent choice.

When deploying something on k8s, always look for the opportunity to write an operator for it. Automating on Kubernetes makes life a lot easier in the long run for your team.

Let's start

Now that we know you can build an operator in Python and understand their usefulness, let's get started with building one.

The operator is a lightweight monitoring tool that checks the status of pods and containers. If something is a miss, it sends a Teams message to your MS Teams channel. Consider this as a tool for scenarios where Grafana or other monitoring tools might be overkill for your project.

We assume you are somewhat familiar with Python, but let's start from the beginning.

CODE

# Creating a folder
mkdir fullstaq-operator

Making a venv to controle and detain the python version and packages.

Python Kubernetes Operator afbeelding
Starting the venv to activate it and you can begin

Python Kubernetes Operator afbeelding
A small tip to make sure the venv is actually active, is to make a pip list. If the list is empty, you know the venv is active.

Python Kubernetes Operator afbeelding
The first step is making a config.py.

In config.py, we use it to load environment variables and set up a logging function, saving the trouble of defining them repeatedly. It might seem a bit overkill now, but making it a habit pays off.

Python Kubernetes Operator afbeelding

Create a Config class where you need to place the necessary environment variables for our operator. If you don't know everything at once, you can add extra details later.

Next, we move to logging. A static method in Python is a special type of method in a class that doesn't receive an implicit reference to the object (the class instance) when called. Instead, it behaves like a regular function associated with the class and can be called without creating an instance of the class.

This can also be done with the cluster. You can place it in Config without a static method, but in this case, we chose to keep it separate to avoid calling the entire class repeatedly.

Now, let's move on to our main script where we can pick up these values and use them.

Python Kubernetes Operator afbeelding

Starting from the top, import the necessary libraries. Additionally, set up the logger from Config.py and then set the cluster. Choose the cluster you want to use, especially for local development where you might have multiple clusters in your context.

Next, you have kubeconfig, allowing you to run the operator locally for testing and in your cluster. This saves the hassle of rebuilding or setting up a local cluster for testing. You can now use any random cluster online/offline to test your script.

Now, let's dive into functions to inspect pods, divided into three variations: namespace, label, or the entire cluster. You can determine the scope of our monitoring tool with an environment variable.

Python Kubernetes Operator afbeelding

In the next step, create a function to determine the action to take when we notice that a pod or container is not working.<Br><br>

<img src="https://objectstore.true.nl/truesite:truefullstaq-com/09/build-python-kubernetes-operator-7.webp" alt="Python Kubernetes Operator afbeelding" width="100%" height="auto">

We look at the pods, and in the second loop, we look at the failed containers, defined in another function.

In handle_failed_pods, we define how to make a request to the Teams channel.

Python Kubernetes Operator afbeelding

Define what we are looking for in the containers in the pod. Then, create a function to determine the scope of our operator.

Python Kubernetes Operator afbeelding

Now, we start with the kopf component. kopf is an operator framework with decorators you can use for operator tasks. We create two – one on startup to start the defined tasks when the executable runs in the pod, and another on a timer to complete tasks at specified intervals.

Now, let's start creating a Dockerfile. It's a simple Dockerfile, often used for Python-based side projects.

Python Kubernetes Operator afbeelding

A work directory is being made, the right scripts are beind copied and requirements are being downloaded. There's no commands. usually put those in the yaml. When we have multiple scripts in one side-project, and we want to run them per container, we usually need only one dockerfile.

Now, we can start with the YAML files to deploy and provide the necessary permissions.

Python Kubernetes Operator afbeelding

We created a deployment where you can fill in the values needed to run the K8s operator.

The deployment is straightforward; the service account is named, and we define the environment variables. With this setup, the variables are not secrets. If running this in a production environment, it's advisable to use secrets. 

Now, we need a service account, a binding, and the rights for the service account. These rights are needed to monitor the pods; otherwise, the operator won't work.

Python Kubernetes Operator afbeelding

Now that you have all the YAMLs, you can build the Docker image and deploy using the YAMLs. Your lightweight monitoring tool is now deployed.

Here is the repo.

Feel free to fork and use it according to your needs. Good luck!

TL;DR

You've learned how to create a simple K8s operator and deploy it.

What can you add to make the operator more mature?

  • Add values as secrets
  • Create a Helm chart
  • Make the code more mature, e.g., by placing the kubeconfig in config.py
  • Add tests ;)