Skip to main content
Platforms need higher-level, domain-aware APIs. Kubernetes exposes a powerful, consistent API for core primitives (Pods, Services, Deployments), but those primitives are low-level. Developers think in domain terms: “I need a database,” not “I need a StatefulSet, a Secret, and a ServiceAccount.” Without a higher-level resource, one logical service maps to many scattered native objects—StatefulSets, ConfigMaps, Secrets, NetworkPolicies—making it hard to reason about platform state. This guide explains how to extend the Kubernetes API using CustomResourceDefinitions (CRDs). You’ll learn:
  • Why built-in resources are insufficient for platform-level abstractions.
  • How the API extension model works.
  • How to author CRDs with correct group, names, scope, and schema.
  • How to validate resources using OpenAPI v3.
  • How CRDs, Custom Resources (CRs), and controllers interact.
A presentation slide titled "Kubernetes Built-In Resources – Limits" that outlines "The Gap" with four limitations: no domain-specific abstractions, no custom validation, no business logic integration, and no platform-specific concepts. Each point has a short explanation (e.g., can't create a single "Database" resource, can't enforce production backup rules, can't trigger workflows on resource changes, and teams/environments aren't native).
When teams rely solely on primitives, queries like “which databases exist?” require scripts that correlate many resources by labels and annotations. With CRDs you can run a single command:
  • kubectl get databases — and get a meaningful list of domain objects.
Kubernetes is designed to be extended. Every API resource follows the same URL pattern: group, version, (optional) namespace, resource. Built-in types and custom types share this pattern (for example, deployments appear at /apis/apps/v1/namespaces/default/deployments). That means CRDs integrate seamlessly with kubectl, RBAC, controllers, GitOps tools, and policy engines.
A presentation slide titled "The Kubernetes API – Extensible by Design" that lists four reasons why this matters: same tools work everywhere, native API experience, consistent patterns, and ecosystem integration. Each reason is shown in a colored, numbered box across the slide.
From the moment you create a CRD, the API server registers the new type and it becomes a first-class API resource. You extend Kubernetes’ API surface without changing Kubernetes core code.
Using CRDs gives you a native API experience: the new resource is reachable through the same endpoints and tooling as built-in types. This ensures compatibility with kubectl, clients, RBAC policies, admission controllers, and GitOps workflows.

CRD structure and important fields

A CustomResourceDefinition declares a new resource type to the API server. Key spec fields you should always consider: Minimal CRD example (top-level structure and where schema belongs):

Versions and conversion

You can serve multiple versions for the same custom resource (for example: v1alpha1, v1beta1, v1). Each version can define its own schema and conversion strategy. Design your versioning and conversion plan to support safe schema evolution and backward compatibility—this avoids breaking consumers or controllers.

OpenAPI v3 schema validation

The CRD’s OpenAPI v3 schema is validated by the API server on create and update. Proper schema design prevents invalid objects from being persisted to etcd and saves controller cycles. Validation capabilities:
  • Type checking: string, integer, object, array, etc.
  • Enum constraints: restrict a field to a set of allowed values.
  • Required fields: ensure essential properties exist.
  • Numeric constraints: minimum, maximum, etc.
  • Nested object validation and arrays.
Example: required fields and an enum constraint
With the schema above:
  • The API server rejects requests that omit spec or spec.size.
  • size accepts only small, medium, or large.
  • replicas must be an integer between 1 and 10.
CRD validation is powerful but not all-expressive. Some rules (like cross-field dependencies or complex business logic) may require admission webhooks or controller-side checks. Always combine schema validation with controller-level safeguards when needed.
Validation occurs at the API layer — controllers do not need to duplicate basic input validation, but they must handle valid states and reconcile external resources.

CRD → CR → Controller: lifecycle and responsibilities

Typical workflow:
  1. Create a CRD to register a new API type and its schema.
  2. Developers create Custom Resources (CRs) using that kind and version.
  3. A controller watches CRs and reconciles desired state to actual infrastructure (creating StatefulSets, Secrets, cloud resources, etc.), and updates the CR’s status.
In short: CRD (schema) → CR (instance) → Controller (implementation logic).
A slide titled "From CRD to Custom Resource" showing a three-box flow: CRD (Schema) → CR (Instance) → Controller (Logic). Below the diagram are short definitions: CRD = class definition, CR = instance of that class, Controller = the logic that makes it real.
Example custom resource that conforms to the CRD shown above:
Apply the CR:
Once applied, Custom Resources behave like native Kubernetes types. Example interactions:

Best practices and mental model

  • CRD = class definition: schema, validation, API surface.
  • CR = instance of the class: desired state specified by users.
  • Controller = implementation logic: reconcile desired to actual state and update status.
Recommended practices:
  • Use a DNS-style API group (e.g., platform.acme.io) to avoid collisions.
  • Provide shortNames for ergonomics (e.g., db).
  • Design robust OpenAPI v3 schemas to catch invalid input early.
  • Plan versioning and conversion strategies before wide adoption.
  • Expose only the fields users need; avoid leaking internal implementation details.
  • Use subresources (status, scale) to cleanly separate desired vs observed state.

Takeaways

  • CRDs let you extend Kubernetes without modifying its core.
  • Custom resources are first-class Kubernetes API objects that integrate with existing tooling and patterns.
  • OpenAPI v3 schema in CRDs validates objects at the API layer and prevents invalid inputs from reaching controllers.
  • The lifecycle flows from CRD → CR → Controller, enabling platforms to expose higher-level abstractions (for example, Database) and provide a native, consistent developer experience.

Watch Video