Kubernetes CRD Management
Kubernetes CRD Management involves creating, deploying, and maintaining custom resources to extend Kubernetes functionality and streamline application operations.
Kubernetes CRD Management is the discipline of designing, versioning, evolving, and safely operating Custom Resource Definitions over their full lifecycle, covering schema design, version conversion, validation strategy, and the operational care required to change or remove a CRD without breaking the objects and controllers that already depend on it.
Schema Design
OpenAPI Validation Schemas
Every CRD version declares an OpenAPI v3 schema under spec.versions[].schema, which the API server uses to validate incoming objects at admission time, rejecting a request before it is ever persisted if it violates type constraints, required fields, or enumerated values.
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: cronbackups.batch.example.com
spec:
versions:
- name: v1
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
required: ["schedule", "target"]
properties:
schedule:
type: string
pattern: '^(\*|[0-9,\-\/]+)( (\*|[0-9,\-\/]+)){4}$'
target:
type: string
retention:
type: integer
minimum: 1
maximum: 365
Structural Schema Requirements
Since Kubernetes 1.16, CRD schemas must be structural — every field must have a known type and additionalProperties must not be used to permit arbitrary unknown fields at the object root — a constraint that enables the API server to prune unknown fields automatically and support features such as kubectl explain and server-side apply for custom resources.
Versioning and Conversion
Multiple Served Versions
A CRD can serve several API versions simultaneously (v1alpha1, v1beta1, v1), with exactly one marked storage: true, meaning objects are persisted internally in that version's shape regardless of which version a client used to create or read them.
spec:
versions:
- name: v1alpha1
served: true
storage: false
- name: v1
served: true
storage: true
Conversion Webhooks
When the schema differs meaningfully between served versions, a conversion webhook is registered to translate objects between versions on read and write, since the API server cannot infer an arbitrary schema migration on its own.
spec:
conversion:
strategy: Webhook
webhook:
clientConfig:
service:
name: crd-conversion-webhook
namespace: extensions
path: "/convert"
conversionReviewVersions: ["v1"]
func (c *conversionWebhook) Convert(req *v1.ConversionRequest) *v1.ConversionResponse {
// translate each object in req.Objects from its source version
// to req.DesiredAPIVersion, returning converted objects
return response
}
Safe Evolution Practices
Additive-Only Changes Within a Version
Adding new optional fields to an existing served version's schema is safe and non-breaking; removing a field, changing a field's type, or making a previously optional field required within the same version name is not, since existing stored objects and existing client code were written against the prior contract.
Deprecation and Removal Lifecycle
Removing a served version follows the same deprecation policy as core Kubernetes APIs: a version is marked deprecated, given a defined support window communicated to consumers, and only removed from served (and eventually from versions entirely) after that window closes and no objects remain stored in that version.
kubectl get postgresclusters.databases.example.com -o jsonpath='{.items[*].apiVersion}' --all-namespaces
Auditing which stored objects still use an older API version, as above, is a required step before removing that version's support, since deleting a served version while objects still exist under it renders those objects unreadable.
Operational Hazards
CRD Deletion Cascades
Deleting a CustomResourceDefinition deletes every custom resource instance of that kind across the entire cluster, in every namespace, as a consequence of removing its storage schema; this is one of the most consequential single API operations available and warrants explicit confirmation before execution in any managed environment.
kubectl get postgresclusters --all-namespaces
Verifying the full inventory of existing custom resource instances, as above, is standard practice before any CRD deletion or version-removal operation.
Storage Version Migration
When the storage version of a CRD changes, previously stored objects remain on disk in their old storage version until they are next written; a storage version migration job (rewriting every existing object with a no-op update) is required to fully complete a version transition and avoid indefinitely mixed-version storage.
Webhook Availability Coupling
Because conversion webhooks are consulted synchronously on every read and write of a multi-version CRD, an unavailable conversion webhook makes every object of that kind briefly unreadable or unwritable cluster-wide, making conversion webhook uptime a direct dependency of API availability for that resource type.
Relationship to the Extension Model and Operator Scope
CRD management is the lifecycle discipline underlying the schema half of the broader Kubernetes extension model: while the reconciliation loop defines how a controller acts on a custom resource, CRD management defines how the shape of that resource itself is allowed to change over time without breaking the controllers, clients, and stored objects that depend on it, making disciplined versioning a prerequisite for any Operator intended to be upgraded safely in a running cluster.