Stage 5 · Platform
Operators, CRDs & Controllers
CRD Versioning
Served versions, storage versions, conversion webhooks, and safe API migration.
CRD Versioning Overview
CRD versioning lets you evolve your API without breaking existing clients. Multiple versions can be served simultaneously. The storage version is what's persisted in etcd. Conversion between versions happens automatically.
| Version Type | Purpose | Example |
|---|---|---|
| Served | Available to clients | v1, v2 |
| Storage | Persisted in etcd | v2 |
| Deprecated | Marked for removal | v1 |
Served Versions
Multiple versions can be served simultaneously. Clients can use any served version. The API server converts requests to the storage version. Deprecate old versions gradually while supporting both old and new.
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: webapps.platform.example.com
spec:
group: platform.example.com
versions:
- name: v1
served: true
storage: false
deprecated: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
replicas:
type: integer
image:
type: string
- name: v2
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
replicas:
type: integer
image:
type: string
resources:
type: objectv1 is served but deprecated and not stored. v2 is served and stored. Existing v1 clients continue to work — the API server converts v1 to v2 for storage. New clients should use v2.
Storage Version
Only one version is stored in etcd. When a client writes v1, the API server converts it to v2 for storage. When a client reads v1, the API server converts from v2. This ensures all data is in the latest format.
spec:
versions:
- name: v1
served: true
storage: false # Not stored
- name: v2
served: true
storage: true # Stored in etcd
- name: v3
served: true
storage: false # Not stored yetstorage: true designates the storage version. All writes are converted to this version before persisting. All reads are converted from this version. Only one version can be the storage version.
Conversion Webhook
Conversion webhooks convert between CRD versions. They handle complex conversions that cannot be expressed with simple field renaming. The webhook receives a ConversionReview request and returns the converted object.
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: webapps.platform.example.com
spec:
conversion:
strategy: Webhook
webhook:
clientConfig:
service:
name: conversion-webhook
namespace: system
path: /convert
caBundle: <base64-encoded-ca>
conversionReviewVersions: ["v1"]
versions:
- name: v1
served: true
storage: false
- name: v2
served: true
storage: trueThe conversion webhook converts between v1 and v2. caBundle verifies the webhook's TLS certificate. conversionReviewVersions lists supported review versions. The webhook must support all served versions.
Multi-Version CRDs
Multi-version CRDs serve multiple versions simultaneously. This enables gradual migration: deprecate v1, introduce v2, and support both during the transition. Clients can migrate at their own pace.
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: webapps.platform.example.com
spec:
group: platform.example.com
conversion:
strategy: Webhook
webhook:
clientConfig:
service:
name: conversion-webhook
namespace: system
path: /convert
versions:
- name: v1
served: true
storage: false
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
replicas: {type: integer}
image: {type: string}
additionalPrinterColumns:
- name: Replicas
type: integer
jsonPath: .spec.replicas
- name: v2
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
replicas: {type: integer}
image: {type: string}
resources: {type: object}
additionalPrinterColumns:
- name: Replicas
type: integer
jsonPath: .spec.replicas
- name: Resources
type: boolean
jsonPath: ".spec.resources != null"v1 and v2 have different schemas. The conversion webhook handles field mapping. additionalPrinterColumns can differ per version. Clients see version-specific output.
Safe API Migration
Safe migration: 1) Add new version (v2) alongside old (v1). 2) Update controllers to handle both versions. 3) Migrate clients to v2. 4) Deprecate v1. 5) Remove v1 after all clients migrate.
# 1. Add v2 version to CRD
# 2. Implement conversion webhook
# 3. Deploy conversion webhook
# 4. Test both versions
kubectl get webapps.v1.platform.example.com
kubectl get webapps.v2.platform.example.com
# 5. Deprecate v1 (add deprecated: true)
# 6. Monitor usage
kubectl get events --field-selector reason=DeprecationWarning
# 7. Remove v1 after migration period
# kubectl get crd webapps.platform.example.com -o yamlMigration is gradual: add new version, migrate clients, deprecate old version, remove old version. Monitor usage to ensure all clients have migrated before removing the old version.
Use kubectl convert to migrate manifests between versions: kubectl convert -f old.yaml --output-version platform.example.com/v2. This automates the field mapping for users.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.