Create a Simple Kubernetes Custom Resource and CRD with kubectl

Able Lv
4 min readJun 4, 2022

--

Photo by Robert Linder on Unsplash

In this article, we will talk about how to create a simple Kubernetes Custom Resource by creating a Custom Resource Definition(CRD) with kubectl.

The following topics are covered in this blog.

  • What is a Kubernetes Resource
  • What is a Custom Resource(CR)
  • What is a CustomResourceDefinition(CRD)
  • Create a CustomResourceDefinition
  • Create a Custom Object
  • Add Additional Printer Columns

What is a Kubernetes Resource

A Kubernetes resource is an endpoint in the Kubernetes API that stores a collection of API objects of a certain kind. For example, the built-in Pods resource contains a collection of Pod objects.

In Kubernetes, there are many built-in resources available. Some examples of Kubernetes resources include:

What is a Custom Resource(CR)

A Custom Resource is an object that extends the Kubernetes API or allows you to introduce your own API into a cluster.

Custom resources can appear and disappear in a running cluster through dynamic registration, and cluster admins can update custom resources independently of the cluster itself.

Once a custom resource is installed, users can create and access its objects using kubectl, just as they do for built-in resources like Pods.

What is a CustomResourceDefinition(CRD)

A CustomResourceDefinition (CRD) defines the name and structure of your custom resource that you want to add to the cluster.

CRDs allow users to create new types of custom resources without adding another API server. Defining a CRD object creates a new custom resource with a name and schema that you specify.

When you create a new CRD, the Kubernetes API Server creates a new RESTful resource path to serve and handle the storage of your custom resource. This frees you from writing your own API server to handle the custom resource.

Create a CustomResourceDefinition

Let’s create a simple CRD. Here is the YAML manifest we’ll use. You can save the following CRD to crd.yaml:

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
# name must be in the form: <plural>.<group>
name: myapps.example.com
spec:
# group name to use for REST API: /apis/<group>/<version>
group: example.com
scope: Namespaced
names:
# kind is normally the CamelCased singular type.
kind: MyApp
# singular name to be used as an alias on the CLI
singular: myapp
# plural name in the URL: /apis/<group>/<version>/<plural>
plural: myapps
versions:
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
x-kubernetes-preserve-unknown-fields: true

The next step is to create the CRD using kubectl:

kubectl apply -f crd.yaml

You’ll get this in response:

customresourcedefinition.apiextensions.k8s.io/myapps.example.com created

Now you can verify it using the kubectl api-resources | grep myapp command. This command prints the supported API resources on the server.

After using it, you should see the following output:

NAME      APIVERSION       NAMESPACED   KIND
myapps example.com/v1 true MyApp

Create a Custom Object

After the CRD object has been created, you can create custom objects. Custom objects can contain custom fields. These fields can contain arbitrary JSON.

To create the custom object, you’ll use the following YAML manifest:

apiVersion: example.com/v1
kind: MyApp
metadata:
name: test-app
spec:
replicas: 3
environment: dev
version: release-1.0.0
language: golang

You can save the above YAML manifest to test-app.yaml, and create the custom object:

kubectl apply -f test-app.yaml

You can then manage your MyApp objects using kubectl. For example:

kubectl get myapp

Should print a list like this:

NAME           AGE
test-app 6s

Resource names are not case-sensitive when using kubectl, and you can use either the singular or plural forms defined in the CRD, as well as any short names.

You can also view the raw YAML data for a custom resource:

➜ kubectl get myapp test-app -o yaml
apiVersion: example.com/v1
kind: MyApp
metadata:
creationTimestamp: "2022-06-04T09:06:33Z"
generation: 1
name: test-app
namespace: test
resourceVersion: "2191741"
spec:
environment: dev
language: golang
replicas: 3
version: release-1.0.0

Delete a CustomResourceDefinition

When you delete a CustomResourceDefinition, the server will uninstall the RESTful API endpoint and delete all custom objects stored in it.

➜ kubectl delete -f crd.yaml
➜ kubectl get myapp

Error from server (NotFound): Unable to list "example.com/v1, Resource=myapps": the server could not find the requested resource (get myapps.example.com)

If you later recreate the same CustomResourceDefinition, it will start out empty.

Add Additional Printer Columns

The kubectl tool relies on server-side output formatting. Your cluster’s API server decides which columns are shown by the kubectl get command. You can customize these columns for a CustomResourceDefinition via the additionalPrinterColumns field. The following example adds the REPLICAS, VERSION, and Age columns.

Save the CustomResourceDefinition to crd.yaml:

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: myapps.example.com
spec:
group: example.com
scope: Namespaced
names:
kind: MyApp
singular: myapp
plural: myapps
versions:
- name: v1
served: true
storage: true
additionalPrinterColumns:
- name: Replicas
type: integer
description: The number of pods launched by the MyApp
jsonPath: .spec.replicas
- name: Version
type: string
jsonPath: .spec.version
- name: Age
type: date
jsonPath: .metadata.creationTimestamp
schema:
openAPIV3Schema:
type: object
properties:
spec:
x-kubernetes-preserve-unknown-fields: true

Create the CustomResourceDefinition:

kubectl apply -f crd.yaml

Create an instance using the test-app.yaml from the previous section. Invoke the server-side printing:

kubectl get myapp test-app

Notice the NAME, REPLICAS, VERSION, and AGE columns in the output:

NAME       REPLICAS   VERSION         AGE
test-app 3 release-1.0.0 4s

Wrap up

In this article, you learned what a Custom Resource is and how to extend the Kubernetes API using the CRD. You can easily create and access custom resource objects using kubectl, just as they do for built-in resources like Pods.

CRDs are useful when combined with a custom controller and used as a declarative API, ensuring that the current and desired states are always in sync. To learn more about what a Kubernetes controller is, see the article below.

Reference

--

--

Able Lv

Cloud Infrastructure Engineer @Airwallex: Kubernetes, DevOps, SRE, Go, Terraform, Istio, and Cloud-Native stuff