TL;DR: For short, I think we can summarize K8s CRD as a Custom API for Kubernetes.
For this definition, it is easier to clarify what is in the standard API for Kubernetes and then explain what is not.
To see what is in the standard API for Kubernetes click here.
A Custom Resource Definition (CRD) is an extension mechanism in Kubernetes that allows you to define your own API objects beyond standard resources like Pods, Services, or Deployments. It acts as a database schema written in YAML (using OpenAPI v3 format) that teaches the Kubernetes API server a new object type, along with its allowed fields and validation rules.
How CRDs Extend the Kubernetes API
The process happens through the Kubernetes API server and its storage system, etcd.
1. Manifest Submission
You apply a YAML manifest of kind CustomResourceDefinition (belonging to the apiextensions.k8s.io API group):
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: databases.example.com
spec:
group: example.com
scope: Namespaced
names:
plural: databases
singular: database
kind: Database
versions:
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
engine:
type: string
replicas:
type: integer
2. Dynamic Endpoint Registration
When kube-apiserver processes this CRD, its built-in apiextensions-apiserver module dynamically constructs and exposes new REST API endpoints:
/apis/example.com/v1/namespaces/{namespace}/databases
No re-compilation or restart of the Kubernetes control plane is required.
3. Schema Validation and Storage
Validation: The API server uses the OpenAPI v3 schema defined in the CRD to validate custom resource objects.
Storage: Once a custom resource passes the API server’s validation and admission processing, its state is persisted in
etcd.
The important distinction here is that the CRD defines the resource type, while an object such as kind: Database is an instance of that custom resource type.
CRD vs. Controller vs. Operator
A CRD alone is just passive data stored in etcd. To make something actually happen when a resource is created, a controller is required:
- CRD (Data/Schema): Defines what the configuration looks like.
- Custom Controller (Logic): A background process (running in a Pod) that runs a continuous control loop (Reconcile Loop) watching for events on those custom endpoints.
- Operator Pattern: The combination of a CRD + Custom Controller that automates complex application lifecycles (e.g., provisioning a Postgres cluster, creating backups, performing failovers).
User / kubectl
│
▼
┌──────────────┐ Validates Schema
│ kube-api ├────────────────────────► [ CRD Definition ]
│ server │
└──────┬───────┘
│ Writes raw JSON/YAML
▼
┌──────────────┐ Watches for changes
│ etcd │◄───────────────────────┐
└──────────────┘ │
┌──────┴──────┐
│ Custom │ (Executes logic: provisions
│ Controller │ actual DBs, clouds, etc.)
└─────────────┘
Request-Handling Flow
When you execute kubectl apply -f my-db.yaml where kind: Database:
1 Authentication & Authorization: kube-apiserver checks RBAC permissions for [example.com/v1/databases](https://example.com/v1/databases).
Schema Validation: The payload is checked against the JSON Schema defined in the CRD.
Persist State: The custom resource instance is written to
etcd.Reconcile Loop: The Custom Controller receives a “Create” watch event, reads
spec.engineandspec.replicas, and provisions the underlying infrastructure/Pods to match that desired state.
Back to Certified Cloud Native Platform Engineering Associate Preparation