A CRD (Custom Resource Definition) is a way to extend the Kubernetes API by defining your own custom objects, just like built-in ones such as Pod, Deployment, etc.
Once you create a CRD:
- Kubernetes adds a new API endpoint (e.g.,
/apis/mydomain.com/v1/widgets) - You can use
kubectlto create, read, update, and delete those new resource types - They behave like native resources, but with custom logic (optional)
🔧 Why Use CRDs?
CRDs are used when:
- Built-in resources are not enough
- You want to represent custom domain-specific objects
- You’re building a Kubernetes Operator (CRD + Controller pattern)
🏗️ Anatomy of a CRD
A CRD YAML has several important sections:
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: widgets.mycompany.com # format: plural.group
spec:
group: mycompany.com
scope: Namespaced # or Cluster
names:
plural: widgets
singular: widget
kind: Widget # Used in YAML's `kind: Widget`
shortNames:
- wd
versions:
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
color:
type: string
size:
type: integer
📌 Key Fields Explained
| Field | Description |
|---|---|
group | Defines API group (like apps, batch, etc.) |
names | Tells Kubernetes how to refer to the resource |
scope | Namespaced or Cluster-wide |
versions | Versioning of the CRD (v1, v1alpha1, etc.) |
schema | Validates the structure of custom resources |
kind | Used in kind: field of custom resource YAMLs |
shortNames | Shorthand for kubectl get commands |
📦 Example Custom Resource (CR)
apiVersion: mycompany.com/v1
kind: Widget
metadata:
name: my-widget
spec:
color: red
size: 42
Once the CRD is registered, you can apply this with kubectl apply -f.
🧠 What Happens When You Create a CRD?
- Kubernetes API server registers a new resource type
- You get a new API endpoint (e.g.,
/apis/mycompany.com/v1/widgets) - You can
kubectl get widgetsor create instances (Custom Resources) - You can optionally write a controller/operator to act on those objects
🤖 CRD + Controller = Kubernetes Operator
A Controller:
- Watches for changes to your CRD (e.g., a new
Widgetis created) - Executes logic (e.g., spins up Pods, validates config, provisions infra)
This is how tools like:
- ArgoCD
- Prometheus Operator
- Cert-Manager
… all work — via CRDs and controllers.
✅ Benefits of CRDs
| Benefit | Description |
|---|---|
| Extends K8s | Define domain-specific objects |
| First-class support | Integrates with kubectl, RBAC, audit logs, CRDs |
| Declarative APIs | Managed just like native objects |
| Evolvable | Supports multiple versions, validation, OpenAPI schemas |
⚠️ Limitations / Gotchas
| Gotcha | Detail |
|---|---|
| No logic on its own | CRDs define structure, not behavior |
| Requires controllers | To react to changes, you need an Operator |
| Schema matters | Bad OpenAPI schema = hard to debug validation |
| Upgrades need care | Changing versions requires versioning strategy (conversion webhooks optional) |
🧪 Tooling Around CRDs
| Tool | Purpose |
|---|---|
kubectl | Manage CRDs and CRs |
kubebuilder | Scaffold Go-based operators |
Operator SDK | Build full-featured Kubernetes operators |
Kopf | Python framework for CRD-based operators |
controller-runtime | Go library for writing controllers |
K9s | TUI to view/interact with CRDs and resources |
📌 Real-World Use Cases
| CRD | Purpose |
|---|---|
certificates.cert-manager.io | TLS certificates automation |
prometheusrules.monitoring.coreos.com | Prometheus alerting rules |
applications.argoproj.io | ArgoCD apps |
installations.operator.tigera.io | Calico network configuration |
