Custom Resource Definitions — Awareness Level
SummaryCovers Custom Resource Definitions as the Kubernetes API...
Covers Custom Resource Definitions as the Kubernetes API...
Covers Custom Resource Definitions as the Kubernetes API extension mechanism. Explains what CRDs are and why they exist, how to discover them with kubectl api-resources and kubectl get crd, the Operator pattern (custom resource + custom controller), and practical interaction with CRD-based resources using cert-manager as an example.
Custom Resource Definitions — Awareness Level
The Kubernetes API ships with a fixed set of resource types: Pods, Deployments, Services, ConfigMaps, Secrets, and roughly fifty others. These built-in resources cover general-purpose workload orchestration, but they cannot represent every domain-specific concept an organization needs. A certificate authority needs to manage Certificate and Issuer objects. A database operator needs PostgresCluster and Backup objects. A service mesh needs VirtualService and DestinationRule objects.
Custom Resource Definitions (CRDs) solve this problem by letting anyone extend the Kubernetes API with new resource types. Once a CRD is installed in a cluster, you interact with the new resource type using the same kubectl commands you use for built-in resources: kubectl get, kubectl describe, kubectl apply, kubectl delete. The API server validates the resource against the CRD’s schema, stores it in etcd, and makes it available through the standard REST API.
The CKAD exam tests CRD awareness — your ability to discover which CRDs are installed, list instances of custom resources, and understand what role they play. You will not be asked to write a CRD definition or build a custom controller.
What Makes a CRD
A CRD has three essential components:
API Group and Version. Every Kubernetes resource belongs to an API group. Built-in Deployments belong to apps/v1. A CRD defines its own group — for example, cert-manager.io/v1. The group prevents naming collisions: two different projects can both define a Certificate resource in different API groups without conflict.
Kind and Plural Name. The CRD specifies the resource kind (e.g., Certificate) and its plural form (e.g., certificates). The plural name determines the URL path in the REST API and the argument you pass to kubectl get.
Schema. The CRD includes an OpenAPI v3 schema that defines the structure of the resource’s spec and status fields. The API server validates incoming resources against this schema, rejecting requests that don’t conform.
When a cluster administrator installs a CRD, the API server dynamically registers a new REST endpoint. From that point forward, the cluster understands the new resource type as if it were built in.
Discovering CRDs in a Cluster
kubectl api-resources
The api-resources command lists every resource type the API server knows about — both built-in and custom:
kubectl api-resources
NAME SHORTNAMES APIVERSION NAMESPACED KIND
pods po v1 true Pod
deployments deploy apps/v1 true Deployment
services svc v1 true Service
certificates cert cert-manager.io/v1 true Certificate
issuers cert-manager.io/v1 true Issuer
clusterissuers cert-manager.io/v1 false ClusterIssuer
...
Custom resources appear alongside built-in ones. You can identify them by their API group — built-in resources use groups like v1, apps/v1, batch/v1, while custom resources use domain-style groups like cert-manager.io/v1 or networking.istio.io/v1.
Filter the list to a specific API group:
kubectl api-resources --api-group=cert-manager.io
NAME SHORTNAMES APIVERSION NAMESPACED KIND
certificates cert cert-manager.io/v1 true Certificate
certificaterequests cr cert-manager.io/v1 true CertificateRequest
issuers cert-manager.io/v1 true Issuer
clusterissuers cert-manager.io/v1 false ClusterIssuer
orders acme.cert-manager.io/v1 true Order
challenges acme.cert-manager.io/v1 true Challenge
This immediately tells you what custom resource types cert-manager has registered and whether they’re namespaced or cluster-scoped.
kubectl get crd
List CRD definitions themselves (the meta-resources that define custom types):
kubectl get crd
NAME CREATED AT
certificates.cert-manager.io 2026-01-15T10:00:00Z
certificaterequests.cert-manager.io 2026-01-15T10:00:00Z
issuers.cert-manager.io 2026-01-15T10:00:00Z
clusterissuers.cert-manager.io 2026-01-15T10:00:00Z
orders.acme.cert-manager.io 2026-01-15T10:00:00Z
challenges.acme.cert-manager.io 2026-01-15T10:00:00Z
Each entry is a CRD object — the definition that tells the API server how to handle the corresponding custom resource type. The name format is <plural>.<group>.
Inspect a specific CRD for its schema and configuration:
kubectl describe crd certificates.cert-manager.io
This shows the CRD’s spec, including the OpenAPI schema, accepted versions, scope (namespaced or cluster-scoped), and any additional printer columns that customize kubectl get output.
The Operator Pattern
A CRD on its own is inert — it defines a data structure the API server can store, but nothing acts on that data. The Operator pattern combines a CRD with a custom controller that watches for instances of the custom resource and takes action to reconcile desired state with actual state.
The pattern follows the same reconciliation loop that drives all of Kubernetes:
- You declare desired state by creating a custom resource (e.g., a
Certificateobject specifying a domain name and an issuer). - The custom controller watches for
Certificateobjects via the API server’s watch mechanism. - The controller acts — it contacts the ACME provider, completes the challenge, retrieves the signed certificate, and stores it in a Kubernetes Secret.
- The controller updates status — it writes the certificate’s expiry date and issuance status back to the
Certificateobject’s.statusfield. - The loop repeats — the controller continuously watches for changes and re-reconciles.
This is the same pattern the Deployment controller uses to manage ReplicaSets and the ReplicaSet controller uses to manage Pods. Operators extend this pattern to domain-specific concerns.
Common Operators You May Encounter
| Operator | Custom Resources | Purpose |
|---|---|---|
| cert-manager | Certificate, Issuer, ClusterIssuer | Automated TLS certificate management |
| Prometheus Operator | Prometheus, ServiceMonitor, AlertmanagerConfig | Monitoring stack management |
| Strimzi | Kafka, KafkaTopic, KafkaUser | Apache Kafka cluster management |
| CloudNativePG | Cluster, Backup, ScheduledBackup | PostgreSQL cluster management |
| Istio | VirtualService, DestinationRule, Gateway | Service mesh configuration |
On the CKAD exam, you won’t install operators. You may encounter an already-installed operator and be asked to interact with its custom resources.
Working with Custom Resources: cert-manager Example
Assume cert-manager is already installed in the cluster. Here’s how you interact with its custom resources using standard kubectl commands.
Listing Custom Resources
kubectl get certificates
NAME READY SECRET AGE
my-app-tls True my-app-tls-cert 5d
api-gateway True api-gw-cert 12d
The output columns may differ from built-in resources because CRDs can define additional printer columns. In this case, cert-manager defines READY and SECRET columns.
Use the short name if one is registered:
kubectl get cert
Describing a Custom Resource
kubectl describe certificate my-app-tls
Name: my-app-tls
Namespace: default
API Version: cert-manager.io/v1
Kind: Certificate
Spec:
Secret Name: my-app-tls-cert
Issuer Ref:
Name: letsencrypt-prod
Kind: ClusterIssuer
Dns Names:
app.example.com
www.app.example.com
Status:
Conditions:
Type: Ready
Status: True
Reason: Ready
Message: Certificate is up to date and has not expired
Not After: 2026-05-15T10:00:00Z
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Issuing 5d cert-manager Issuing certificate as Secret does not exist
Normal Generated 5d cert-manager Stored new private key in temporary Secret
Normal Requested 5d cert-manager Created new CertificateRequest resource
Normal Issuing 5d cert-manager The certificate has been successfully issued
The describe output follows the same structure as built-in resources: metadata, spec, status, conditions, and events. The events trail shows the controller’s actions — in this case, cert-manager requesting and obtaining a certificate.
Creating a Custom Resource
Custom resources are created with kubectl apply, the same as any Kubernetes object:
# certificate.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: staging-tls
namespace: default
spec:
secretName: staging-tls-cert
issuerRef:
name: letsencrypt-staging
kind: ClusterIssuer
dnsNames:
- staging.example.com
kubectl apply -f certificate.yaml
The API server validates the resource against the CRD’s schema. If the YAML doesn’t conform — a required field is missing, a field has the wrong type — the API server rejects it with a validation error, the same as for built-in resources.
Deleting a Custom Resource
kubectl delete certificate staging-tls
When you delete a custom resource, the controller may perform cleanup actions (removing the associated Secret, revoking the certificate, etc.), depending on how the operator is implemented.
Getting Custom Resource YAML
kubectl get certificate my-app-tls -o yaml
This outputs the full resource definition including metadata, spec, and status — useful for creating similar resources or debugging issues.
Key Takeaways for the Exam
- CRDs extend the API. They add new resource types that behave like built-in resources.
- Discovery commands:
kubectl api-resourcesshows all resource types;kubectl get crdlists installed CRD definitions. - Interaction is standard kubectl:
get,describe,apply,deleteall work on custom resources. - Operators = CRD + Controller. The CRD defines the data structure; the controller performs the reconciliation logic.
- You won’t create CRDs on the exam. You’ll interact with custom resources that are already installed.
The distinction between “I need to build this” and “I need to use this” is critical for exam time management. If a task mentions a custom resource type, use kubectl api-resources to verify it exists, then interact with it using standard kubectl commands. Don’t spend time trying to understand the CRD’s internal implementation.