What a CRD Actually Does
What a CRD Actually Does
A Custom Resource Definition registers a new kind with the API server: group, versions, and scope. Custom resources are stored in etcd, served over the same REST paths, validated by admission, and governed by RBAC exactly like built-ins.
The apiextensions.k8s.io/v1 API enforces structural schemas: every field needs a declared type, unknown fields are pruned, and invalid values are rejected at admission. A CRD alone changes nothing at runtime — it is data storage until a controller reconciles it.
Authoring the Definition
Authoring the Definition
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata: { name: backups.db.example.com }
spec:
group: db.example.com
scope: Namespaced
names:
plural: backups
kind: Backup
shortNames: [bk]
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec: { type: object, properties: { schedule: { type: string } } }
status: { type: object, properties: { lastRun: { type: string } } }
subresources: { status: {} }
additionalPrinterColumns:
- name: SCHEDULE
type: string
jsonPath: .spec.schedule
Apply the CRD, create a Backup, then kubectl get bk shows the column. With subresources.status, spec and status update through separate endpoints — controllers cannot clobber user edits.
Pitfalls and Interview Angles
Pitfalls and Interview Angles
Deleting the CRD cascades. Every custom resource of that kind is garbage-collected — one kubectl delete crd can wipe an entire application's state.
Status fights. Without the status subresource, a controller PATCHing status can overwrite spec changes (and vice versa); with it, the endpoints are independent.
Version evolution. storage: true may be set on only one version; changing it requires a conversion strategy (webhook) once old stored objects must translate. served: false hides a version from the API without deleting data.
Finalizers. metadata.finalizers blocks deletion until a controller removes them — essential for cleanup, but a crashed controller leaves objects stuck Terminating.
Interview angle: distinguish CRD from CR, served from storage, and describe what happens on CRD deletion.
Quiz
1. What is the difference between a CRD and a custom resource?
2. Why enable the status subresource?
3. What happens when you delete a CRD?
Flashcards
Question
Structural schema
Click to reveal answer
Answer
Fully typed OpenAPI v3 schema required by apiextensions/v1; unknown fields are pruned and validation is enforced at admission.
Question
served vs storage
Click to reveal answer
Answer
served exposes a version on the API; exactly one storage version is persisted in etcd.
Question
Printer columns
Click to reveal answer
Answer
additionalPrinterColumns shape kubectl get output with jsonPath-derived columns.
Question
CRD deletion cascade
Click to reveal answer
Answer
Deleting a CRD deletes all its custom resources — controllers and finalizers must plan for that.
Question
Finalizer on a CR
Click to reveal answer
Answer
metadata.finalizer blocks delete until a controller performs cleanup and removes it; a dead controller leaves it stuck.
Revision Notes
Key Takeaways
- 1. CRDs register types; custom resources are their stored instances in etcd
- 2. v1 structural schemas plus the status subresource give validation and safe controller writes
- 3. Deletion cascade and finalizers are the lifecycle facts interviewers probe hardest
Interview Tips
- • Answer CRD vs CR, served vs storage, and deletion cascade as a three-part story
- • Explain when you need a conversion webhook versus a simple served-version bump
Cheat Sheet
CRD = structural OpenAPI schema + printer columns + status subresource. One storage version; served toggles exposure. CRD delete cascades to all CRs; finalizers block deletion.
Continue Learning
Before You Start
- No prerequisites listed.