Skip to main content
mastering ckad certified kubernetes application developer

Custom Resource Definitions — Awareness Level

8 min read Chapter 68 of 87
Summary

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:

  1. You declare desired state by creating a custom resource (e.g., a Certificate object specifying a domain name and an issuer).
  2. The custom controller watches for Certificate objects via the API server’s watch mechanism.
  3. The controller acts — it contacts the ACME provider, completes the challenge, retrieves the signed certificate, and stores it in a Kubernetes Secret.
  4. The controller updates status — it writes the certificate’s expiry date and issuance status back to the Certificate object’s .status field.
  5. 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

OperatorCustom ResourcesPurpose
cert-managerCertificate, Issuer, ClusterIssuerAutomated TLS certificate management
Prometheus OperatorPrometheus, ServiceMonitor, AlertmanagerConfigMonitoring stack management
StrimziKafka, KafkaTopic, KafkaUserApache Kafka cluster management
CloudNativePGCluster, Backup, ScheduledBackupPostgreSQL cluster management
IstioVirtualService, DestinationRule, GatewayService 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

  1. CRDs extend the API. They add new resource types that behave like built-in resources.
  2. Discovery commands: kubectl api-resources shows all resource types; kubectl get crd lists installed CRD definitions.
  3. Interaction is standard kubectl: get, describe, apply, delete all work on custom resources.
  4. Operators = CRD + Controller. The CRD defines the data structure; the controller performs the reconciliation logic.
  5. 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.