| name | k8s-crd-design |
| description | CRD schema, webhook, RBAC, and reconcile loop patterns |
Kubernetes CRD Design Patterns
Use these patterns when designing and implementing CRDs, webhooks, controllers, and RBAC for Kubernetes operators.
1. Problem Framing
Before writing code, answer:
- Summarize the user problem in one sentence.
- List the CRD's top 3 responsibilities.
- Identify safety risks (what could go wrong if the controller misbehaves?).
2. CRD Schema Design
Propose a CRD with:
- Spec fields: Required fields with types and validation markers. Use kubebuilder markers (
+kubebuilder:validation:*).
- Status fields: Observed state, conditions, and last-reconciled generation.
- Defaults: Use
+kubebuilder:default:= markers for sensible defaults.
- Validation: Use
+kubebuilder:validation:Enum, +kubebuilder:validation:Minimum, +kubebuilder:validation:Pattern as appropriate.
- Printer columns: Add
+kubebuilder:printcolumn for useful kubectl get output.
Example pattern:
type MyResource struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec MyResourceSpec `json:"spec,omitempty"`
Status MyResourceStatus `json:"status,omitempty"`
}
3. Webhook Design
Validating Webhook
- Block invalid creates and updates.
- Enforce immutable fields on update.
- Validate cross-field constraints.
- Return clear error messages.
Mutating Webhook
- Only default safe, optional fields.
- Never mutate fields the user explicitly set.
- Add labels/annotations the controller needs.
- Keep mutations minimal and predictable.
Failure Policy
- Dev:
Ignore (don't block the cluster if webhook is down)
- Production:
Fail (safety over availability)
4. Reconcile Loop Outline
Standard reconcile pattern:
- Fetch the CR by name. If not found, return (deleted).
- Check for deletion timestamp — handle finalizers.
- Compute desired state from spec.
- For each owned resource:
- Get current state
- Compare with desired state
- Create, update, or delete as needed
- Update CR status with observed state and conditions.
- Requeue if needed (e.g., waiting for external resource).
Key principles:
- Idempotent: Safe to call multiple times with the same input.
- Level-triggered: React to current state, not events.
- Owner references: Set on all created resources for garbage collection.
- Status conditions: Use standard condition types (Ready, Progressing, Degraded).
5. RBAC Minimization
List the minimal permissions the controller needs:
- Own CRD: get, list, watch, update (status subresource), patch
- Owned resources: get, list, watch, create, update, patch, delete
- Events: create, patch (for recording events)
- Webhook: no extra RBAC (handled by API server)
Avoid:
- Cluster-wide permissions unless the CRD is cluster-scoped
- Wildcard resources or verbs
- Permissions on resources the controller doesn't manage
6. Test Outline
Minimum test coverage:
- Unit tests: Reconcile logic with mock client (table-driven)
- Envtest tests: Full API server + etcd for webhook validation
- Example manifests: Valid and invalid CRs for manual testing
var _ = BeforeSuite(func() {
testEnv = &envtest.Environment{
CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")},
WebhookInstallOptions: envtest.WebhookInstallOptions{
Paths: []string{filepath.Join("..", "config", "webhook")},
},
}
})