CRDs

Custom Resource Definitions (CRDs) allow you to extend the Kubernetes API with your own resource types. Understanding CRDs is important because they enable you to model your applications and infrastructure as native Kubernetes resources, integrate external systems, and build domain-specific abstractions.

Think of CRDs like adding new forms to a filing system. Kubernetes comes with standard forms (Pods, Services, Deployments), but sometimes you need custom forms for your specific needs. CRDs let you define new forms (resource types) that work just like the built-in ones—you can create them, list them, watch them, and manage them with kubectl.

What are CRDs?

A Custom Resource Definition (CRD) is a way to extend the Kubernetes API by defining new resource types. Once you create a CRD, you can create, read, update, and delete instances of that resource type just like built-in resources.

Custom Resources vs Built-in Resources

Built-in resources (Pods, Services, Deployments):

  • Defined in Kubernetes core code
  • Available in all clusters
  • Can’t be modified or removed

Custom resources (defined via CRDs):

  • Defined by you
  • Specific to your cluster
  • Can be created, modified, or deleted
  • Work like built-in resources

Why Use CRDs?

CRDs enable several powerful use cases:

Domain-Specific Abstractions

Model your applications and infrastructure as Kubernetes resources:

apiVersion: example.com/v1
kind: Database
metadata:
  name: my-database
spec:
  type: postgresql
  version: "14"
  replicas: 3
  storage: 100Gi

API Integration

Integrate external systems into Kubernetes:

apiVersion: networking.example.com/v1
kind: LoadBalancer
metadata:
  name: my-lb
spec:
  provider: aws
  type: application
  listeners:
  - port: 80
    protocol: HTTP

Application-Specific Resources

Define resources specific to your applications:

apiVersion: apps.example.com/v1
kind: WebApplication
metadata:
  name: my-app
spec:
  frontend:
    image: my-frontend:1.0
    replicas: 3
  backend:
    image: my-backend:1.0
    replicas: 2
  database:
    type: postgresql

CRD Structure

A CRD defines:

  • API group and version - Where the resource lives
  • Resource name - Plural and singular names
  • Scope - Namespaced or cluster-scoped
  • Schema - Structure of the resource (spec, status)
  • Validation - Rules for valid resources
  • Subresources - Status, scale, etc.

Example CRD

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: databases.example.com
spec:
  group: example.com
  versions:
  - name: v1
    served: true
    storage: true
    schema:
      openAPIV3Schema:
        type: object
        properties:
          spec:
            type: object
            properties:
              type:
                type: string
              version:
                type: string
              replicas:
                type: integer
              storage:
                type: string
          status:
            type: object
            properties:
              phase:
                type: string
  scope: Namespaced
  names:
    plural: databases
    singular: database
    kind: Database
    shortNames:
    - db

Custom Resources

Once you create a CRD, you can create custom resources:

apiVersion: example.com/v1
kind: Database
metadata:
  name: my-database
  namespace: production
spec:
  type: postgresql
  version: "14"
  replicas: 3
  storage: 100Gi
status:
  phase: Running
  endpoints:
  - my-database-0.example.com:5432

This works just like built-in resources:

# Create
kubectl create -f database.yaml

# List
kubectl get databases

# Get details
kubectl get database my-database -o yaml

# Update
kubectl apply -f database.yaml

# Delete
kubectl delete database my-database

CRDs and Controllers

CRDs by themselves just define the resource structure. To make them useful, you typically need controllers (operators) that:

  • Watch for custom resources
  • Reconcile desired state with actual state
  • Create other Kubernetes resources
  • Manage external systems
  • Update status based on actual state
graph TB CRD[CRD Definition] --> CustomResource[Custom Resource] CustomResource --> Controller[Controller/Operator] Controller --> K8sResources[K8s Resources<br/>Pods, Services, etc.] Controller --> External[External Systems<br/>Cloud APIs, etc.] Controller --> Status[Update Status] Status --> CustomResource style CRD fill:#e1f5ff style CustomResource fill:#fff4e1 style Controller fill:#e8f5e9 style K8sResources fill:#f3e5f5 style External fill:#f3e5f5

Common CRD Use Cases

Operators

Operators use CRDs to manage complex applications:

  • Database operators - Manage database instances
  • Monitoring operators - Deploy and manage monitoring stacks
  • CI/CD operators - Manage CI/CD pipelines
  • Application operators - Manage application lifecycles

Infrastructure as Code

Model infrastructure as Kubernetes resources:

  • Load balancers - Define load balancers as resources
  • DNS records - Manage DNS as resources
  • Storage - Define storage configurations
  • Networking - Model network topologies

GitOps Integration

Use CRDs with GitOps tools:

  • ArgoCD Applications - Application CRDs
  • Flux Sources - Git/Helm source CRDs
  • Custom workflows - Define workflows as resources

CRD Best Practices

Schema Design

  • Define clear spec and status sections
  • Use OpenAPI schema for validation
  • Version your CRDs appropriately
  • Plan for schema evolution

Naming

  • Use clear, descriptive names
  • Follow Kubernetes naming conventions
  • Use appropriate API groups
  • Choose good shortNames

Validation

  • Validate input in CRD schema
  • Use admission webhooks for complex validation
  • Provide clear error messages
  • Validate early and often

Versioning

  • Plan for API versioning
  • Support multiple versions during transitions
  • Deprecate old versions properly
  • Document version changes

CRD Limitations

CRDs have some limitations:

  • No defaulting - Can’t set defaults in CRD (use webhooks)
  • Limited validation - Complex validation requires webhooks
  • No subresources by default - Status subresource must be enabled
  • Schema evolution - Changing schemas requires care
  • Performance - Large numbers of CRDs can impact API server

When to Use CRDs

Good Use Cases

Domain-specific abstractions - Model your domain ✅ Application operators - Manage complex applications ✅ Infrastructure modeling - Model infrastructure as resources ✅ API integration - Integrate external systems ✅ GitOps workflows - Define workflows as resources

When Not to Use

Simple configuration - Use ConfigMaps instead ❌ Simple deployments - Use Deployments instead ❌ No controller needed - CRDs without controllers are limited ❌ Over-engineering - Don’t create CRDs for everything

CRDs vs Operators

CRDs - Define the resource structure Operators - Provide the logic to manage resources

You typically use both together:

  • CRD defines what the resource looks like
  • Operator (controller) provides the management logic

Key Takeaways

  • CRDs extend the Kubernetes API with custom resource types
  • Custom resources work like built-in resources
  • CRDs define structure, controllers provide logic
  • Common use cases include operators and infrastructure modeling
  • CRDs enable domain-specific abstractions
  • Plan for schema evolution and versioning
  • Use CRDs when you need custom abstractions, not for simple cases

See Also