CRDs
Kubernetes allows users to extend its API through Custom Resource Definitions (CRDs), enabling the creation of domain-specific resources tailored to applications or workflows. CRDs are essential for scenarios like managing stateful applications, defining custom controllers, or integrating with external systems. This section explains how to define and implement CRDs to extend Kubernetes' capabilities.
Understanding Custom Resource Definitions (CRDs)¶
A Custom Resource Definition is a YAML file that defines a new resource type, specifying its structure, behavior, and API version. CRDs are stored in the crd.k8s.io API group and are managed by the Kubernetes API server. Each CRD defines a kind (e.g., MyDatabase) and includes a spec (desired state) and status (observed state) for instances of the resource.
Key Components of a CRD¶
apiVersion: Specifies the API group and version (e.g.,crd.k8s.io/v1).kind: The type of resource (e.g.,CustomResourceDefinition).spec: Defines the structure of the custom resource, including:scope:NamespacedorCluster(determines visibility).names: The plural and singular names for the resource (e.g.,databasesanddatabase).validation: Rules for validating custom resource instances.additionalProperties: Optional fields for extensibility.
Example: A CRD for a custom Database resource:
apiVersion: crd.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: databases.example.com
spec:
scope: Namespaced
names:
plural: databases
singular: database
kind: Database
validation:
openAPIV3Schema:
properties:
spec:
properties:
size: {type: integer}
engine: {type: string}
Creating a Custom Resource Definition¶
To create a CRD, apply the YAML file using kubectl:
Using Custom Resources¶
Once a CRD is defined, users can create instances of the custom resource. For example, to create a Database resource:
apiVersion: example.com/v1
kind: Database
metadata:
name: my-database
spec:
size: 10
engine: PostgreSQL
validation rules and store it as a normal Kubernetes object.
Managing Custom Resources with Controllers¶
CRDs are often paired with controllers that reconcile the actual state of resources with the desired state. A controller typically:
1. Watches for changes to the custom resource.
2. Applies business logic to update related resources (e.g., provisioning a database).
3. Updates the status field to reflect the current state.
Example: A basic controller in Go using the Kubernetes client library:
func main() {
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err)
}
// Watch for Database resources
informer := informers.NewSharedInformerFactory(clientset, 0)
dbInformer := informer.InformerFor(&corev1.Database{}, func() cache.StoreProvider {
return cache.NewStore(cache.MetaNamespaceKeyFunc)
})
// Reconcile logic
dbInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
Update: func(oldObj, newObj any) {
// Logic to update database state
},
})
informer.Start(context.TODO())
informer.WaitForCacheSync(context.TODO())
}
Best Practices and Considerations¶
- Versioning: Use semantic versioning for CRD APIs to manage backward compatibility.
- Validation: Define strict validation rules in the
validationfield to prevent invalid configurations. - Namespacing: Use
Namespacedscope for most custom resources to avoid global pollution. - Security: Restrict access to CRDs using Kubernetes Role-Based Access Control (RBAC).
- Testing: Validate CRDs in isolated environments before deploying to production.
Key takeaways¶
- CRDs allow you to extend Kubernetes' API with domain-specific resources.
- A CRD defines the structure and behavior of a custom resource type.
- Controllers are essential for managing the lifecycle of custom resources.
- Follow best practices like versioning, validation, and RBAC to ensure robustness.
- CRDs are a foundational tool for building custom controllers and workflows in Kubernetes.