How to write KUBERNETES OPERATOR

Estimated read time 7 min read

The intention of writing a Kubernetes (K8s) operator keeps growing in my mind. I started reading articles, exploring GitHub repositories, and asking my colleagues about it. While I can’t say it was entirely successful, the intention is still there.

As a backend developer who works with Kubernetes every day, I have always wanted to write an operator to expand the boundaries of my knowledge. However, obstacles arose that prevented me from achieving this goal.

This is the story of writing gobackup-operator while I was in the military . tl;dr : Skip directly to the “In-depth project” section

Sharpen your knife and keep it from chopping wood

The intention of writing a Kubernetes (K8s) operator keeps growing in my mind. I started reading articles, exploring GitHub repositories, and asking my colleagues about it. While I can’t say it was entirely successful, the intention is still there.

The result of all this effort is a series of tutorial projects stored in my GitHub account .

I should mention that the practice process started about a year ago when I was first introduced to Kubernetes. I first watched Guru’s tutorial to learn about CKAD and then Nana’s YouTube tutorial .

reduced to ashes

I was sent to do military service.

There was no internet connection or even an electronic device. Instead, we had nothing but hardcover books, volleyball, and stunning sunrise and sunset views to entertain us.

In this case, the idea of ​​creating an operator is fading away. All I cared about was eating, reading, and enjoying the occasional freedom (vacation). However, sometimes this freedom is short-lived, as a commander once commented:

The joy of the holiday ends the moment you leave the barracks.

The training course was over and I started working as an employee in the office but the lack of internet connectivity was felt there too! In the evenings, I leave the office and work on a job I love. Sometimes, you perform better in a limited amount of time. So, from 4pm to 9pm, I had to create something special. To me, it’s really special!

It’s enough if you don’t chirp

After all, with the help of this series , I managed to write another Kubernetes operator from the tutorial! But this time, it was different.

My colleague has developed a backup system, but it doesn’t seem to be working very well. So they explored another solution and came across a project called gobackup , which was designed to regularly back up databases and push them to storage. The problem is that the project does not include support for the etcd database. Therefore, they decided to contribute to the project by adding etcd support to meet the requirements . This eventually resulted in a new version .

During my absence, they decided to develop a Kubernetes operator based on this. This is an important step for me. When they shared it with me, I eagerly checked out the project and thought, “Finally, this is it. The operator is about to be created. Yay!”

While reading about the project, I noticed an issue in the project’s readme file. One of the links leads to a 404 page. I proactively fixed the issue and submitted a pull request.

The owner embraced it. 🙂

After encountering such an open attitude, one of my colleagues suggested that we could put this operator under the gobackup organization so that more people can contribute to its development.

I opened an issue and proposed a repository under the gobackup organization , and there is still an openness to collaborate.

During the day, I served in the military, and at night, I worked on the gobackup-operator project.

Go deep into the project

I first set up my environment.

Fortunately, I already have Golang, Docker, and kubectl installed on my computer. Through previous practice, I am already familiar with local machine Kubernetes clusters (such as Kind) and tools for creating operators (such as kubebuilder).

Therefore, I started the operator code.

$ kubebuilder init --domain gobackup.io --repo github.com/gobackup/gobackup-operator

Then I went ahead and created the API for the operator:

$ kubebuilder create api --group gobackup --version v1 --kind Backup
Create Resource [y/n]
y
Create Controller [y/n]
y

The same goes for databases and storage:

$ kubebuilder create api --group database.gobackup --version v1 --kind PostgreSQL
Create Resource [y/n]
y
Create Controller [y/n]
y

$ kubebuilder create api --group storage.gobackup --version v1 --kind S3
Create Resource [y/n]
y
Create Controller [y/n]
y

Modify API

I modified the API according to the specific requirements of the project:

// Backup is the Schema for the backups API
type Backup struct {
 metav1.TypeMeta   `json:",inline"`
 metav1.ObjectMeta `json:"metadata,omitempty"`

 Spec   BackupSpec   `json:"spec,omitempty"`
 Status BackupStatus `json:"status,omitempty"`

 BackupModelRef BackupModelRef `json:"backupModelRef,omitempty"`
 StorageRefs    []StorageRef   `json:"storageRefs,omitempty"`
 DatabaseRefs   []DatabaseRef  `json:"databaseRefs,omitempty"`
}

Then modify the Reconcile method

//+kubebuilder:rbac:groups=gobackup.io,resources=backups,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=gobackup.io,resources=backups/status,verbs=get;update;patch
//+kubebuilder:rbac:groups=gobackup.io,resources=backups/finalizers,verbs=update
func (r *BackupReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
 // reconcile implementation
}

test

Before you test it, you need to prepare a backup test database. Therefore, create a PostgreSQL deployment using the gobackup-operator-postgres-deployment.yaml file:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: postgres-deployment
spec:
  selector:
    matchLabels:
      app: postgres
  replicas: 1
  template:
    metadata:
      labels:
        app: postgres
    spec:
      containers:
      - name: postgres
        image: postgres:14.11
        env:
        - name: POSTGRES_USER
          value: ""
        - name: POSTGRES_PASSWORD
          value: ""
        - name: PGDATA
          value: "/var/lib/postgresql/data/pgdata"
        volumeMounts:
        - mountPath: /var/lib/postgresql/data
          name: postgredb
      volumes:
      - name: postgredb
        persistentVolumeClaim:
          claimName: postgres-pvc

POSTGRES_USERRemember to modify and POSTGRES_PASSWORDapply it in the manifest :

kubectl apply -f example/gobackup-opetator-postgres-deployment.yaml,
example/gobackup-opetator-postgres-service.yaml

In addition, I also added some resources for testing in the Kubernetes cluster, including deployments, roles, cluster roles, service accounts, etc., all of which can be found in the gobackup-operator/example/ directory.

Therefore, apply these checklists to add basic resources:

kubectl apply -f example/gobackup-opetator-serviceaccount.yaml,
gobackup-opetator-pvc.yaml,
gobackup-opetator-namespace.yaml,
gobackup-opetator-clusterrolebinding.yaml,
gobackup-opetator-clusterrole.yaml

Then there is the storage and database list:

kubectl apply -f example/gobackup-opetator-storage/*
kubectl apply -f example/gobackup-opetator-database/*

Using the following manifest, I was able to run the operator on my local machine:

kubectl apply -f example/gobackup-opetator-deployment.yaml

Therefore, whenever a Backup or CronBackup object is created or changed, the operator performs the necessary tasks.

To create a backup model to set up backup configuration:

kubectl apply -f example/gobackup-opetator/gobackup-opetator-backupmodel.yaml

Applying one of the manifests (backup or cronbackup) in the gobackup-operator/example/gobackup-operator directory will trigger the operator to run the backup:

kubectl apply -f example/gobackup-opetator/gobackup-opetator-cronbackup.yaml

In conclusion

At first I was embarrassed to make such a small change in the readme. It feels like one of those PRs you make just to submit to Hacktoberfest.

But then I considered its effectiveness. Even those single-line commits made an impact. Who knows, if I hadn’t made the changes to the README file, I might not have created this operator.

Small steps matter!

Feel free to check out and contribute here . If you need to make changes to the README file, please don’t hesitate. 😉

You May Also Like

More From Author

+ There are no comments

Add yours