Kubernetes Custom Resources, Custom Resource Definition (CRD) & Controllers

Published: (January 17, 2026 at 11:34 PM EST)
3 min read
Source: Dev.to

Source: Dev.to

SHARON SHAJI

Kubernetes is not powerful because of Pods or Services.
It’s powerful because it can be extended without modifying Kubernetes itself.

That extensibility comes from Custom Resources + CRDs + Controllers.

If you don’t understand these three properly, you’re not really using Kubernetes — you’re just deploying YAML.

Why CRDs Exist

Kubernetes solves generic infrastructure problems:

  • Scheduling
  • Networking
  • Storage
  • Scaling

But real companies have domain‑specific problems:

  • “Deploy a model”
  • “Provision a database”
  • “Create a service mesh rule”
  • “Manage certificates”

Instead of hard‑coding these into Kubernetes, it gives us a way to define our own APIs.

Framework

ComponentPurpose
CRDDefines a new API type
Custom ResourceInstance of that API
ControllerLogic that makes it real

Mental Model (Important)

Kubernetes itself does nothing with your CRDs – it only stores them.
If you create a CRD without a controller, Kubernetes will happily accept it and do absolutely nothing. That’s not a bug; that’s the design.

What Is a Custom Resource (CR)?

A Custom Resource is a new object type in Kubernetes, just like:

  • Pod
  • Service
  • Deployment

You can create your own, e.g.:

  • Database
  • Application
  • MLModel
  • Certificate
  • Gateway

Example

kubectl get databases
kubectl apply -f myapp.yaml

Kubernetes doesn’t care what Database means.

What Is a CRD (CustomResourceDefinition)?

A CRD defines a new API schema inside Kubernetes. Think of it as:

“Hey Kubernetes, here is a new kind of object. Please store it.”

A CRD specifies:

  • API group
  • Version
  • Kind
  • Schema (validation)

Simple CRD Example

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: databases.mycompany.io
spec:
  group: mycompany.io
  scope: Namespaced
  names:
    plural: databases
    singular: database
    kind: Database
  versions:
    - name: v1
      served: true
      storage: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                engine:
                  type: string
                version:
                  type: string
                storage:
                  type: string

After applying this CRD:

kubectl get databases

Kubernetes now recognizes Database as a valid object — nothing more.

Creating a Custom Resource (CR)

apiVersion: mycompany.io/v1
kind: Database
metadata:
  name: user-db
spec:
  engine: postgres
  version: "15"
  storage: 20Gi

Apply it:

kubectl apply -f database.yaml

Result:

  • Stored in etcd
  • No Pod created
  • No database started

This is where most beginners get confused.

Why Controllers Are Mandatory

A Controller is the brain. It:

  • Watches Custom Resources
  • Compares desired state vs actual state
  • Reconciles the difference

Without a controller:

  • CRD = dead schema
  • CR = useless YAML

Controller Reconciliation Loop

Every controller follows this loop:

Observe → Compare → Act → Repeat

In code terms:

while True:
    desired_state = cr.spec
    actual_state = cluster_reality
    if desired_state != actual_state:
        fix_it()

This loop never stops.

How CRD + Controller Work Together

User
  |
  | kubectl apply
  v
Kubernetes API Server
  |
  v
etcd (stores CR)
  |
  v
Controller watches CR
  |
  v
Controller creates / updates:
  - Pods
  - Services
  - PVCs
  - ConfigMaps

Real Example: Database Operator

Custom Resource

apiVersion: mycompany.io/v1
kind: Database
metadata:
  name: user-db
spec:
  engine: postgres
  version: "15"
  storage: 20Gi

Controller Logic

IF Database CR is created:
  - Create StatefulSet
  - Create PVC
  - Create Service

IF Database CR is deleted:
  - Cleanup resources

Kubernetes doesn’t know databases. Your controller does.

Desired vs Actual State

Desired State (CR):
  Database:
    engine: postgres
    replicas: 1

Actual State (Cluster):
  StatefulSet: missing

Controller Action:
  Create StatefulSet

If someone deletes the StatefulSet manually, the controller recreates it.

CRDs vs Deployments

FeatureDeploymentCRD
Built‑inYesNo
Controller includedYesOnly if you write one
Logic locationKubernetesYou
DescriptionA Deployment is just a CRD + controller shipped by Kubernetes.

Istio Uses CRDs

Istio extends Kubernetes using CRDs such as:

  • VirtualService
  • DestinationRule
  • Gateway

Example

kind: VirtualService
spec:
  hosts:
    - myapp
  http:
    - ...

Istio CRDs Diagram

route:
  - destination:
      host: myapp-v2

Istio Controllers Convert This Into

  • Envoy config
  • Traffic routing
  • Load balancing

Note: Istio doesn’t modify Kubernetes. It extends it properly.

Why Companies Build Products Using CRDs

CRDs allow:

  • Kubernetes‑native APIs
  • Declarative behavior
  • kubectl‑first UX
  • Strong reconciliation guarantees

Used by:

  • ArgoCD
  • Crossplane
  • Cert‑Manager
  • Prometheus Operator
  • Istio

All follow the same pattern.

Common Mistakes

  • “CRD automatically creates resources”
  • Writing logic inside YAML
  • Ignoring .status fields
  • Treating CRDs as config files

CRDs are APIs, not configs.

When Should You Use CRDs?

Use CRDs when:

  • You manage lifecycle, not just deployment
  • You need reconciliation
  • You’re building a platform

Do not use CRDs for:

  • Static configs
  • One‑time jobs
  • Simple values

Final Takeaway

  • CRDs define WHAT you want
  • Controllers define HOW it happens
  • Kubernetes enforces the loop

If you understand this, you understand Kubernetes beyond YAML.

Back to Blog

Related posts

Read more »

Rapg: TUI-based Secret Manager

We've all been there. You join a new project, and the first thing you hear is: > 'Check the pinned message in Slack for the .env file.' Or you have several .env...

Technology is an Enabler, not a Saviour

Why clarity of thinking matters more than the tools you use Technology is often treated as a magic switch—flip it on, and everything improves. New software, pl...