Extending K8S API

Ever found yourself thinking, “Kubernetes is awesome, but I wish it could do this specific thing just for my setup”? Well, guess what? It probably can. Kubernetes isn’t just about managing those swanky Pods and Services; it’s like a LEGO set, and with the right pieces, you can build pretty much anything.

Enter the world of Custom Resource Definitions, or CRDs for the cool kids. Imagine being able to teach your Kubernetes new tricks without waiting for the next big release. That’s exactly what CRDs let you do!

In this blog post, we will explore how to extend the Kubernetes API with Custom Resource Definitions (CRDs).

Topics To be covered :

  1. Registering a Custom API in Golang
  2. Creating a Custom Resource Definition ( CRD ) to Register our Custom Resource

A Look at the General API of Kubernetes Resources

1. The Basics: API Groups and Versions

  • API Groups: To make its API more extensible and modular, Kubernetes has different API groups like core, apps, batch, extensions, and more. These groups represent various functionalities and components.
  • Versions: Each group can have multiple versions, typically marked as v1, v1beta1, etc. This is because the Kubernetes API evolves over time, and different versions can coexist.

2. Resources and Kinds

  • Resources: These are a persistent entity in the Kubernetes system. Pods, Services, and Nodes are all examples of resources.
  • Kinds: This denotes the type of the resource. When you create or read a resource, you work with its kind. For instance, the kind for a Pod is Pod, and for a Service, it’s Service.

3. Object Metadata Every Kubernetes resource comes with metadata. This section usually includes details like:

  • name: Unique within a namespace, used to identify the resource.
  • namespace: Helps with the resource’s scope. Some resources are cluster-scoped (like Node), while others are namespace-scoped (like Pod).
  • labels and annotations: Key-value pairs that you can attach to resources for various purposes, from organizational patterns to notes.

4. Spec and Status Almost every Kubernetes resource has these two main fields:

  • Spec (Specification): This is what you provide. It’s your desired state for the resource.
  • Status: This is what Kubernetes provides back. It tells you the current state of the resource and how it compares to the spec.

5. API Endpoints For every resource, there are specific API endpoints. These are the URLs you’d hit if you were to interact directly with the Kubernetes API server. For instance, /api/v1/namespaces/{namespace}/pods/{pod} would be an endpoint for a specific pod.


Registering a Custom API in Golang

Before you can use a custom resource in Kubernetes, you need to define it, usually in Golang. Here is how you can do it.

  1. Define your types in Go. Use tags to define how the fields are serialized in JSON or YAML.
package v1

type MyCustomResourceSpec struct {
    Field1 string `json:"field1,omitempty"`
    Field2 int    `json:"field2,omitempty"`
}

type MyCustomResource struct {
    metav1.TypeMeta   `json:",inline"`
    metav1.ObjectMeta `json:"metadata,omitempty"`

    Spec   MyCustomResourceSpec   `json:"spec,omitempty"`
    Status MyCustomResourceStatus `json:"status,omitempty"`
}

type MyCustomResourceList struct {
    metav1.TypeMeta `json:",inline"`
    metav1.ListMeta `json:"metadata,omitempty"`
    Items           []MyCustomResource `json:"items"`
}
  1. Next, we must create a deep copy to make our API object compatible with the k8s object. Since the Object Interface requires DeepCopyObject()
type Object interface {
    GetObjectKind() schema.ObjectKind
    DeepCopyObject() Object
}

To generate a deepcopy we would use controller-gen run the below command to install at $GOPATH/bin/

go install sigs.k8s.io/controller-tools/cmd/controller-gen@latest
  1. We need to put kubebuilder tags to tell the controller-gen which object we need to create deecopy. The tag we use is // +kubebuilder:object:root=true as suggested here. We need to put this tag on MyCustomResource and MyCustomResourceList to generate deepcopy for that as given below. This would generate a file zz_deepcopy.go in the same directory.
// +kubebuilder:object:root=true
type MyCustomResource struct {
    metav1.TypeMeta   `json:",inline"`
    metav1.ObjectMeta `json:"metadata,omitempty"`

    Spec   MyCustomResourceSpec   `json:"spec,omitempty"`
    Status MyCustomResourceStatus `json:"status,omitempty"`
}

// +kubebuilder:object:root=true
type MyCustomResourceList struct {
    metav1.TypeMeta `json:",inline"`
    metav1.ListMeta `json:"metadata,omitempty"`
    Items           []MyCustomResource `json:"items"`
}

Creating a Custom Resource definition (CRD) to Register the Custom Resource

Since now we have created a Go scheme for our custom resource we need to register this resource in the k8s. We have to create a definition for that i.e. custom resource definition

We would use controller-gen to create a CRD manifest. Go to the root of the repo and run :
controller-gen crd:crdVersions=v1 paths="./..." output:dir="./crd"

This command will:

  • Scan for types in the current module (the paths=”./…” part).
  • Generate CRDs in the v1 format (crd:crdVersions=v1).
  • Place the generated CRD YAML files in the ./crd directory.

If you have a Kubernetes cluster ready and you want to apply the CRDs, you can use kubectl: kubectl apply -f ./crd

Blog Pundits: Sandeep Rawat

OpsTree is an End-to-End DevOps Solution Provider.

Connect with Us

Leave a Reply