- CRD: extends K8s API with custom resource types
- Custom resource: instance of a CRD (like Pod is instance of core API)
- Operator: controller that watches Custom Resources and acts on them
- Building operators/controllers: not tested; know how to consume existing CRDs
CRD schema
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: widgets.example.com # <plural>.<group>
spec:
group: example.com
scope: Namespaced
names:
plural: widgets
singular: widget
kind: Widget
versions:
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
size:
type: string
Custom resource instance
apiVersion: example.com/v1
kind: Widget
metadata:
name: my-widget
spec:
size: large
kubectl
| Task | Command |
|---|---|
| List all CRDs | kubectl get crd |
| Describe a CRD | kubectl describe crd <name> |
| List instances | kubectl get <kind> -A |
| Install CRD | kubectl apply -f crd.yaml |
| Explain custom resource | kubectl explain <kind> |
kubectl api-resources --api-group=example.com
Exam workflow: create a custom resource from existing CRD
CRD is pre-installed. Task: create an instance.
# 1. Find the CRD
kubectl get crd | grep -i <keyword>
# e.g. → animes.animes.k8s.io
# 2. Inspect schema for valid field names
kubectl get crd <crd-name> -o json \
| jq '.spec.versions[].schema.openAPIV3Schema.properties.spec.properties'
# or without jq:
kubectl describe crd <crd-name> # look for Validation section
# 3. Find apiVersion and short name
kubectl api-resources | grep -i <keyword>
# → animes an animes.k8s.io/v1alpha1 true Anime
# 4. Create the custom resource
cat <<EOF | kubectl apply -f -
apiVersion: animes.k8s.io/v1alpha1
kind: Anime
metadata:
name: my-anime
spec:
animeName: "Death Note"
episodeCount: 37
EOF
# 5. Verify
kubectl get an my-anime
Field validation gotcha
CRDs can have minimum, maximum, enum, pattern constraints. API server rejects violations immediately:
The Anime "my-anime" is invalid: spec.episodeCount: Invalid value: 10:
spec.episodeCount in body should be greater than or equal to 24
Check schema first with jq or describe crd.
Exam gotchas
- CRD
metadata.namemust be<plural>.<group> apiVersionon custom resource =<group>/<version>kubectl api-resources | grep <kind>faster than memorising apiVersions- Scope (
true= Namespaced,false= Cluster): whether to add-n <ns> - Without jq:
kubectl get crd <name> -o yaml | grep -A 30 'openAPIV3Schema'