Kubernetes CRD Schema Management
Kubernetes CRD Schema Management defines and enforces the structure of custom resources, ensuring consistency and reliability in Kubernetes-based applications.
Kubernetes CRD Schema Management is the practice of authoring, generating, testing, and maintaining the OpenAPI validation schema embedded in a Custom Resource Definition, encompassing the tooling that derives schemas from source code, the defaulting and pruning behavior the API server applies at admission time, and the workflow for evolving a schema without silently breaking objects already stored under it.
Authoring Approaches
Hand-Written OpenAPI Schemas
A schema can be written directly as OpenAPI v3 YAML, giving full manual control but requiring the author to keep the schema synchronized by hand with whatever code actually consumes the resource.
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
replicas:
type: integer
minimum: 1
maximum: 10
storageClassName:
type: string
Generated Schemas from Source Annotations
Tooling such as controller-gen (used by the Kubebuilder and Operator SDK ecosystems) derives the OpenAPI schema directly from Go struct tags and marker comments, keeping the schema mechanically synchronized with the controller's actual data model.
type PostgresClusterSpec struct {
// +kubebuilder:validation:Minimum=1
// +kubebuilder:validation:Maximum=10
Replicas int32 `json:"replicas"`
// +kubebuilder:validation:Enum=gp3;io2;standard
StorageClassName string `json:"storageClassName,omitempty"`
}
controller-gen crd:crdVersions=v1 paths="./api/..." output:crd:dir=./config/crd/bases
Defaulting Behavior
Schema-Level Defaults
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
retentionDays:
type: integer
default: 30
A default value declared in the schema is applied by the API server itself at admission time whenever the field is omitted from a submitted object, meaning defaulting happens once, at creation, and is persisted into the stored object rather than being recomputed on every read.
Defaulting Webhooks vs. Schema Defaults
Simple, static defaults belong in the schema; defaults that depend on other field values or external state (computing a default replica count based on a referenced node pool's size, for instance) require a mutating admission webhook instead, since schema-level default values cannot express conditional logic.
Pruning and Preservation
Automatic Pruning Under Structural Schemas
With a structural schema, any field submitted that is not declared anywhere in the schema is silently dropped by the API server before the object is stored, rather than being rejected or persisted as unknown data, which protects the resource's shape but also means a typo in a field name fails silently rather than with a validation error unless additionalProperties: false is explicitly set to reject unknowns instead of pruning them.
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
additionalProperties: false
properties:
replicas:
type: integer
Cross-Field and Business-Rule Validation
CEL-Based Validation Rules
Common Expression Language rules embedded via x-kubernetes-validations express constraints that span multiple fields or encode business logic beyond simple type and range checks, evaluated synchronously at admission time without a separate webhook round trip.
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
x-kubernetes-validations:
- rule: "self.minReplicas <= self.maxReplicas"
message: "minReplicas must not exceed maxReplicas"
- rule: "!has(oldSelf.storageClassName) || self.storageClassName == oldSelf.storageClassName"
message: "storageClassName is immutable after creation"
The second rule above demonstrates immutability enforcement by comparing the incoming object (self) against the previously stored object (oldSelf), a pattern that previously required a validating webhook and is now expressible directly in the schema.
Testing Schema Changes
Dry-Run Validation
kubectl apply --dry-run=server -f updated-postgrescluster.yaml
Server-side dry-run submits an object through the full admission chain, including schema validation and any registered webhooks, without persisting it, making it the standard way to verify a schema change accepts or correctly rejects representative sample objects before rolling the change out.
Schema Compatibility Testing in CI
Operator projects commonly maintain a corpus of representative custom resource YAML files exercised in CI against each schema revision, catching accidental breaking changes (a tightened enum, a newly required field) against realistic objects before the schema reaches a production cluster where existing stored objects could be invalidated.
Relationship to CRD Management, Spec Structure, and Version Management
Schema management is the content-authoring discipline underlying the structural fields described in CRD spec structure, and it is the layer where the safe-evolution rules from broader CRD management (additive-only changes, structural schema requirements) and the sequencing rules from version management are actually put into practice: a schema change is where those policies either hold or are violated, making rigorous authoring and testing of the schema itself the point where CRD lifecycle discipline is enforced in the day-to-day of Operator development.