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

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

A custom resource definition (CRD) file defines your own object kinds and lets the API Server handle the entire lifecycle. Deploying a CRD into the cluster causes the Kubernetes API server to begin serving the specified custom resource.

When you create a new custom resource definition (CRD), the Kubernetes API Server reacts by creating a new RESTful resource path, that can be accessed by an entire cluster or a single project (namespace). As with existing built-in objects, deleting a project deletes all custom objects in that project.

Creating Custom Resource Definitions

To create a CRD, open a YAML file and enter the fields in the following example.

Example YAML file for a Custom Resource Definition
apiVersion: apiextensions.k8s.io/v1beta1 (1)
kind: CustomResourceDefinition
metadata:
  name: crontabs.stable.example.com (2)
spec:
  group: stable.example.com (3)
  version: v1 (4)
  scope: Namespaced (5)
  names:
    plural: crontabs (6)
    singular: crontab (7)
    kind: CronTab (8)
    shortNames:
    - ct (9)
1 Use the apiextensions.k8s.io/v1beta1 API.
2 Specify a name for the definition. This must be in the <plural-name><group> format using the values from the group and plural fields.
3 Specify a group name for the API. An API group is a collection of objects that are logically related. For example, all batch objects like Job or ScheduledJob could be in the batch API Group (such as batch.api.example.com). A good practice is to use a fully-qualified-domain name of your organization.
4 Specify a version name to be used in the URL. Each API Group can exist in multiple versions. For example: v1alpha, vibeta, v1.
5 Specify whether the custom objects are available to a project (Namespaced) or all projects in the cluster (Cluster).
6 Specify the plural name to be used in the URL. The plural field is the same as a resource in an API URL.
7 Specify a singular name to be used as an alias on the CLI and for display.
8 Specify the kind of objects that can be created. The type can be in CamelCase.
9 Specify a shorter string to match your resource on the CLI.

By default, a custom resource definition is cluster-scoped and available to all projects.

After configuring the definition file, create the object:

oc create -f <file-name>.yaml

A new RESTful API endpoint is created at:

/apis/<spec:group>/<spec:version>/<scope>/*/<names-plural>/...

For example, using the example file, the following endpoint would be created:

/apis/stable.example.com/v1/namespaces/*/crontabs/...

This endpoint URL can then be used to create and manage custom objects. The kind of object is based on the spec.kind field of the Custom Resource Definition object you created.

Create Custom Objects

After the custom resource definition object has been created, you can create custom objects.

Custom objects can contain custom fields. These fields can contain arbitrary JSON.

In the following example, the cronSpec and image custom fields are set in a custom object of kind CronTab. The kind CronTab comes from the spec.kind field of the custom resource definition object you created above.

Example YAML file for a Custom Object
apiVersion: "stable.example.com/v1" (1)
kind: CronTab (2)
metadata:
  name: my-new-cron-object (3)
spec: (4)
  cronSpec: "* * * * /5"
  image: my-awesome-cron-image
1 Specify the group name and API version (name/version) from the custom resource definition.
2 Specify the type in the custom resource definition.
3 Specify a name for the object.
4 Specify conditions specific to the type of object.

After configuring the object file, create the object:

oc create -f <file-name>.yaml

Manage Custom Objects

You can then manage your custom resources.

To get information on a specific kind of custom resource, enter:

oc get <kind>

For example:

oc get crontab

NAME                 KIND
my-new-cron-object   CronTab.v1.stable.example.com

Note that resource names are not case-sensitive, and you can use either the singular or plural forms defined in the CRD, as well as any short name. For example:

oc get crontabs
oc get crontab
oc get ct

You can also view the raw JSON data:

oc get <kind> -o yaml

You should see that it contains the custom <1> cronSpec and <2> image fields from the YAML you used to create it:

oc get ct -o yaml

apiVersion: v1
items:
- apiVersion: stable.example.com/v1
  kind: CronTab
  metadata:
    clusterName: ""
    creationTimestamp: 2017-05-31T12:56:35Z
    deletionGracePeriodSeconds: null
    deletionTimestamp: null
    name: my-new-cron-object
    namespace: default
    resourceVersion: "285"
    selfLink: /apis/stable.example.com/v1/namespaces/default/crontabs/my-new-cron-object
    uid: 9423255b-4600-11e7-af6a-28d2447dc82b
  spec:
    cronSpec: '* * * * /5' (1)
    image: my-awesome-cron-image (2)

Finalizers

Custom objects support finalizers, which allow controllers to implement conditions that must be completed before the object can be deleted.

You can add a finalizer to a custom object like this:

apiVersion: "stable.example.com/v1"
kind: CronTab
metadata:
  finalizers:
  - finalizer.stable.example.com

The first delete request on an object with finalizers sets a value for the metadata.deletionTimestamp field instead of deleting the object. This triggers controllers watching the object to execute any finalizers they handle.

Each controller then removes the finalizer from the list and issues the delete request again. This request deletes the object only if the list of finalizers is empty, meaning all finalizers are done.