✦ For everyone, free.

Practical knowledge for real and everyday life

Home

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
}
Stored Object = Convert ( Served Version Storage Version )

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.

v1alpha1 v1beta1 Conversion Storage: v1