Stage 3 · Build
Kubernetes Controllers in Go
CRD Design
Validation, conversion, subresources, and printer columns for usable custom resources.
CRD Structure
Custom Resource Definitions extend Kubernetes with your own API types. A well-designed CRD is clear, validated, and follows Kubernetes conventions. The spec defines desired state; the status reports observed state.
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: webapps.myorg.io
spec:
group: myorg.io
versions:
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
replicas:
type: integer
minimum: 1
maximum: 10
image:
type: string
required: ["replicas", "image"]
status:
type: object
properties:
readyReplicas:
type: integer
conditions:
type: array
subresources:
status: {}
scope: Namespaced
names:
plural: webapps
singular: webapp
kind: WebApp
shortNames: ["wa"]The CRD defines the API schema. spec is the desired state the user provides. status is the observed state the controller writes. subresources.status enables kubectl get and kubectl patch on the status subresource.
Types Generation
Define Go types for your CRDs and use code generators to create deepcopy methods, client code, and informer factories.
# Install controller-gen
go install sigs.k8s.io/controller-tools/cmd/controller-gen@latest
# Generate deepcopy methods
controller-gen object paths="./api/..."
# Generate CRD manifests
controller-gen crd paths="./api/..." output:crd:dir=./config/crd
# Generate RBAC and webhook manifests
controller-gen rbac paths="./..." output:rbac:dir=./config/rbac
controller-gen webhook paths="./..." output:webhook:dir=./config/webhookcontroller-gen reads your Go types and generates CRD manifests, deepcopy methods, and RBAC rules. Run it after changing types. The generated files should be committed to version control.
Validation
Validation prevents invalid resources from being created. Use OpenAPI v3 schema validation for basic checks and CEL (Common Expression Language) for complex rules.
Subresources
Subresources extend the API with custom endpoints. The status subresource is the most common — it lets users update spec and status independently and enables kubectl status commands.
# Status subresource
subresources:
status: {}
# Scale subresource (for HPA integration)
subresources:
scale:
specReplicasPath: .spec.replicas
statusReplicasPath: .status.readyReplicas
labelSelectorPath: .status.labelSelector
# Use with kubectl
kubectl get webapp my-app
kubectl patch webapp my-app --type merge -p '{"status":{"readyReplicas":3}}'
# Scale subresource
kubectl scale webapp my-app --replicas=5The status subresource separates spec changes from status changes. Status updates do not trigger spec reconciliation. The scale subresource integrates with HPA and kubectl scale.
Printer Columns
Printer columns control what kubectl get displays. They make your resources readable at a glance without requiring -o yaml.
versions:
- name: v1
additionalPrinterColumns:
- name: Replicas
type: integer
jsonPath: .spec.replicas
- name: Ready
type: integer
jsonPath: .status.readyReplicas
- name: Image
type: string
jsonPath: .spec.image
- name: Age
type: date
jsonPath: .metadata.creationTimestamp
- name: Status
type: string
jsonPath: ".status.conditions[?(@.type=='Ready')].status"
priority: 0Printer columns are displayed by kubectl get. jsonPath extracts values from the resource. priority controls which columns are shown by default — higher priority columns hide on narrow terminals. The Ready condition example shows how to extract values from condition arrays.
Version Conversion
When you need to change the CRD schema, create a new API version. Conversion webhooks translate between versions, allowing old and new clients to coexist.
Think about how users will interact with your CRD via kubectl. What do they need to see at a glance? What fields do they need to edit? Good CRD design makes kubectl a powerful management tool for your custom resources.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.