5 min guide to write kubernetes operator using Operator SDK

Published Feb 16, 2021 (Updated Feb 16, 2021) by Girish Talekar • Pinned ⭐
#Operator SDK #Kubernetes operator #k8sResourceCloner



5 min guide to write kubernetes operator using Operator SDK

When i started writing the k8s operator first time it took me couple of hours to figure out how to write an operator. After doing some reading and searching i found that it is quit simple and easy to write an operator in k8s.

Writing an operator to Clone/Copy Kubernetes resource from one namespace to another

You can find this operator in my github repo

Installation of and configuration of operator-sdk :

$ mkdir -p $GOPATH/src/github.com/operator-framework
$ cd $GOPATH/src/github.com/operator-framework
$ git clone https://github.com/operator-framework/operator-sdk
$ cd operator-sdk
$ git checkout master
$ make dep
$ make install
$ operator-sdk -h

Steps to create the operator :

$ operator-sdk init --domain=example.com --repo=github.com/example-inc/k8sResourceCloner
$ operator-sdk create api --group=cache --version=v1alpha1 --kind=K8sResourceCloner
// K8sResourceClonerSpec defines the desired state of K8sResourceCloner
type K8sResourceClonerSpec struct {
	// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
	// Important: Run "make" to regenerate code after modifying this file

	// Foo is an example field of K8sResourceCloner. Edit K8sResourceCloner_types.go to remove/update
	FromNamespace string   `json:"fromNamespace"`
	ToNamespaces  []string `json:"toNamespaces"`
	ResourceNames []string `json:"resourceNames"`
}

// K8sResourceClonerStatus defines the observed state of K8sResourceCloner
type K8sResourceClonerStatus struct {
	// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
	// Important: Run "make" to regenerate code after modifying this file
	Nodes []string `json:"nodes"`
}
$ make generate
$ make manifests

Implement the controller

  1. Reconcile loop
// Fetch the K8sResourceCloner instance
	k8sResoureCloner := &cachev1alpha1.K8sResourceCloner{}
	err := r.Get(ctx, req.NamespacedName, k8sResoureCloner)
	if err != nil {
		if errors.IsNotFound(err) {
			// Request object not found, could have been deleted after reconcile request.
			// Owned objects are automatically garbage collected. For additional cleanup logic use finalizers.
			// Return and don't requeue
			log.Info("K8sResourceCloner resource not found. Ignoring since object must be deleted")
			return ctrl.Result{}, nil
		}
		// Error reading the object - requeue the request.
		log.Error(err, "Failed to get K8sResourceCloner")
		return ctrl.Result{}, err
	}

	configMapInstance := &corev1.ConfigMap{}
	for j := 0; j < len(k8sResoureCloner.Spec.ResourceNames); j++ {
		err = r.Get(ctx, types.NamespacedName{Name: k8sResoureCloner.Spec.ResourceNames[j],
			Namespace: k8sResoureCloner.Spec.FromNamespace}, configMapInstance)
		if err == nil {
			for i := 0; i < len(k8sResoureCloner.Spec.ToNamespaces); i++ {
				if err == nil {
					newConfigMap := newConfigMap(configMapInstance, k8sResoureCloner.Spec.ToNamespaces[i])
					err = r.Create(ctx, newConfigMap)
					if err != nil {
						return ctrl.Result{}, err
					}
				}
			}
			break
		}
	}
func newConfigMap(cm *corev1.ConfigMap, ns string) *corev1.ConfigMap {
	labels := map[string]string{
		"app": cm.Name,
	}
	data := make(map[string]string)
	for k, v := range cm.Data {
		data[k] = v
	}

	return &corev1.ConfigMap{
		ObjectMeta: metav1.ObjectMeta{
			Name:      cm.Name,
			Namespace: ns,
			Labels:    labels,
		},
		Data: data,
	}
}
  1. Setup Manager
func (r *K8sResourceClonerReconciler) SetupWithManager(mgr ctrl.Manager) error {
	return ctrl.NewControllerManagedBy(mgr).
		For(&cachev1alpha1.K8sResourceCloner{}).
		Owns(&corev1.ConfigMap{}).
		Complete(r)
}

How to run:

Run locally outside the cluster

$ make install run

Update config/samples/cache_v1alpha1_k8sresourcecloner.yaml

fromNamespace : from which the resources need to be cloned

toNamespaces: in which namespace it need to be cloned, multiple namespaces are allowed

resourceNames: the resource name which need to be copied, multiple resource name are allowed

apiVersion: cache.example.org/v1alpha1
kind: K8sResourceCloner
metadata:
  name: k8sresourcecloner-sample
spec:
  fromNamespace : default
  toNamespaces: 
  - test
  - demo
  resourceNames:  
  - test-configMap

Create a K8sResourceCloner CR

kubectl apply -f config/samples/cache_v1alpha1_k8sresourcecloner.yaml

Resources:

https://sdk.operatorframework.io/docs/building-operators/golang/tutorial/



*****

© 2021, Girish Talekar | Github Profile.