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.