CRD Design Best Practices
Custom resources: design for evolution.
Schema
CRD design is the discipline of producing well-formed Custom Resource Definitions. Good CRDs validate inputs, separate desired from observed state, and evolve cleanly. Poor CRDs produce confusion, breakage, and operational burden.
What schema design provides:
- OpenAPI v3 schema.: CRDs use OpenAPI v3 schemas. The schema declares the structure; the API server validates inputs against it; invalid resources are rejected before they reach the controller.
- Validates inputs.: The validation is at the API server. Bad inputs are rejected; the controller does not have to defend against them; the discipline is built into Kubernetes.
- Required fields.: The schema declares which fields are required. Resources missing required fields are rejected; the user gets clear errors; the discipline is enforced.
- Defaults.: Optional fields can have defaults. The user does not have to specify everything; sensible defaults reduce friction; the resource is concise.
- Enums.: Fields with bounded values use enums. Invalid values are rejected; the schema documents the allowed values; the API is self-describing.
Schema design is the foundation. Good schemas produce good APIs; poor schemas produce confused users.
Status
The Kubernetes pattern separates spec from status. Spec is what the user requested (desired state); status is what is observed (actual state). The separation is fundamental to Kubernetes' reconciliation model.
- Separate spec from status.: The CRD declares two distinct subresources. spec holds the user's intent; status holds the controller's observations.
- Spec equals desired.: The user's manifest specifies what they want. The controller reads spec; reconciles toward it; the actual state evolves toward the desired.
- Status equals observed.: The controller writes status. Conditions, observed counts, error messages all are status fields; the user sees what is actually happening.
- Standard pattern.: The pattern is universal in Kubernetes. Native resources (Deployment, StatefulSet) follow it; custom resources should too; the consistency supports user expectations.
- Status updates via subresource.: The status subresource has its own RBAC. Controllers can update status without write access to spec; the user's spec is protected.
Spec/status separation is the Kubernetes-native pattern. Following it produces resources that feel native.
Evolve
CRDs evolve over time. Versioning conventions and conversion webhooks support evolution; the discipline is planning for change before launch.
- Versioning v1alpha1 to v1beta1 to v1.: The Kubernetes versioning convention progresses through alpha, beta, and stable (v1). Each stage has different stability commitments; users understand the maturity.
- Conversion webhooks for migration.: When the schema changes, conversion webhooks translate between versions. Old resources continue working; new resources use the new schema; the transition is bounded.
- Plan before launch.: The team thinks about evolution before launching the CRD. What might change? How do we handle the change? The planning prevents painful migrations later.
- Don't break v1.: Once at v1, the schema is stable. Breaking changes require new versions; the existing v1 keeps working; users' resources are not invalidated.
- Document the evolution path.: The team documents how the CRD will evolve. Users know what to expect; the discipline is communicated; surprises are minimized.
CRD design is one of those Kubernetes platform engineering disciplines that pays off across the CRD's lifetime. Nova AI Ops integrates with custom resources, surfaces usage patterns, and supports teams operating CRD-driven platforms.