RefactorFirst
RefactorFirst
Published on

Part 1: How to Create a Kubernetes Custom Resource Definition (CRD)

Part 1: How to Create a Kubernetes Custom Resource Definition (CRD)
7 min read
Authors

This is a multi-part article on how you can create a Kubernetes Custom Resource Definition (CRD) and then create a Kubernetes controller to handle CRD instance creation requests. In this article, we would be exploring how we can create your own Kubernetes CRD.

Understanding How Kubernetes Works with Resources

Before we move on to creating our first CRD and controller, we have to understand some concepts behind how Kubernetes resource management works.

Let’s look at the diagram

Kubernetes working

As you see in the diagram, we have an API server, scheduler, controller, and database. When we use the command kubectl to create a resource, we are actually talking to the API server and the API server merely stores the resource in the database. Now, we have a scheduler, which keeps on asking the API server if there are some resources created.

Once the scheduler finds that a pod has to be created, it then inserts into the database via the API server the reference of the node where the pod will be created.

Next, Kubelets running on the various worker nodes start calling the API server and check if any pods have to be created on that particular node. Kubelets are nothing but controllers themselves.

So in this article, we will see how you can create your own Kubernetes CRD, and then create an instance of the CRD.

Pre-requisites

  • A working Kubernetes cluster. (local or remote)
    If you don't have one, you can always run a K3s cluster locally or you can use a Kind Kubernetes cluster. You can read about starting a Kind Kubernetes cluster here.
  • Basic knowledge of working with “Kubectl” commands to create, get or delete a resource.

Creating a Kubernetes Custom Resource Definition (CRD)

Let's create a simple Kubernetes Custom Resource Definition and view its various parts.

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: my-crds.com.amrut.prabhu
spec:
  group: com.amrut.prabhu
  names:
    kind: my-crd
    plural: my-crds
  scope: Namespaced
  versions:
    - name: v1
      served: true
      storage: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            apiVersion:
              type: string
            kind:
              type: string
            metadata:
              type: object
            spec:
              type: object
              properties:
                my-own-property:
                  type: string

This is the most minimalistic definition to create your own Kubernetes CRD.

To understand this, Let’s break it up into two parts.

Part 1: Define the metadata and definition of the CRD

Part 2: Define the schema of the CRD instances that we will create later.

Understanding The Kubernetes Custom Resource Definition Format

Let's Look at Part 1.

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: my-crds.com.amrut.prabhu
spec:
  group: com.amrut.prabhu
  names:
    kind: my-crd
    plural: my-crds
  scope: Namespaced
  versions:
    - name: v1
      served: true
      storage: true

Here we define the “Kind” of our resource, i.e we want to create a CRD and we provide it a name. The name has to be of the format <CRD plural Name>.<Group name> , ie. “my-crds . com.amrut.prabhu ”. Next, in the spec section, we define the name and the plural name of the kind we are creating. This is the type we will specify while creating a new instance later.

Next, we define that the CRD will be scoped to a namespace and in the version section, we specify the version of this CRD to v1. When we want to create a new version of this definition, we will just bump up this version number.

Lastly, we have served property that defines if this CRD is enabled to be used in the cluster and storage refers to if this version of the CRD will be stored. At a time you can have only one version of the CRD that can be stored.

This was all about defining our CRD. Let’s look at the schema of the CRD.

Understanding CRD Schema

schema:
  openAPIV3Schema:
    type: object
    properties:
      apiVersion:
        type: string
      kind:
        type: string
      metadata:
        type: object
      spec:
        properties:
          my-own-property:
            type: string
        type: object

In this, we define the schema using the Open API version 3 standards. We specify the top level as an object which has some properties.

Now, some of the absolutely required properties are:

  • apiVersion: To define the version of the CRD we will be using.
  • kind: The type of the CRD
  • metadata: The metadata which will be added such as the name, annotations, etc. This will be of the type Object.
  • spec: This defines the custom specifications properties you want to provide.

Now, in the above schema, I have specified only one property i.e my-own-property in the spec section. You can also define a property of type object having its own properties.

Let's look at how the CRD is mapped to our CRD instance.

CRD to CRD instance Mapping

As you can see above, the arrows make it simple to understand which property from the CRD maps to the CRD instance. This is how our custom resource definition is mapped to the actual instance YAML file.

With this, let's first apply our CRD to the Kubernetes cluster.

Adding Kubernetes CRD to the Kubernetes Cluster

In order to use our CRD, We will have to add it to our Kubernetes Cluster. Let’s install this using the following command

kubectl apply -f my-crd.yaml
CRD apply

Now, after creating the CRD, we are going to create our first CRD instance. We will use the same instance YAML file from above.

apiVersion: com.amrut.prabhu/v1
kind: my-crd
metadata:
  name: my-custom-resource-instance
spec:
  my-own-property: 'My first CRD instance'
CRD Instance Apply

With this, we just created our first Kubernetes CRD and then created our first CRD instance.

After creating the instance nothing really happened. Only the instance object was created and stored in the Kubernetes database.

But we want it to do something when we create an instance.

For this, we will need to implement a controller that will handle creating instance requests and do something with it. We will explore this in our next article.

You can find CRD yaml files on GitHub here.

So, subscribe to my newsletter below and follow me on Twitter to know when the article is published.

Enjoy!!