Kubernetes has become the de facto standard for container orchestration, underpinning modern cloud-native platforms and driving innovation within the Cloud Native Computing Foundation (CNCF). Its extensibility through Custom Resource Definitions (CRDs) and controllers enables developers to tailor Kubernetes to their unique needs, bridging the gap between abstract infrastructure and application-specific logic. This article explores the core concepts of CRDs, controllers, and their role in building scalable platforms, while clarifying common misconceptions and practical implementation strategies.
CRDs allow developers to define new resource types within Kubernetes, extending its API to model domain-specific concepts. A CRD consists of four key components:
apiextensions.k8s.io/v1
).Widget
, Pizza
).CRDs enable the creation of resources like PostgreSQL
databases, where attributes such as name, environment type (dev/prod), and configuration parameters are enforced through validation rules. This flexibility allows Kubernetes to abstract complex systems, from legacy applications to cloud services, into unified APIs.
Controllers are the core mechanism for managing Kubernetes resources. They operate as event-driven applications, running as Pods, and monitor specific resources to ensure the actual state matches the desired state through a process called reconciliation. Key features include:
Deployment
) and external systems (e.g., bare-metal infrastructure, cloud APIs).For example, the Deployment
controller manages ReplicaSets and Pods, while a custom controller like Promise
might automatically generate API resources and backend services. This extensibility is critical for building domain-specific platforms.
Controllers are a general-purpose mechanism for resource management, while Operators are specialized controllers focused on managing the lifecycle of complex applications. Operators, introduced by Red Hat, provide a structured framework for encapsulating operational knowledge (e.g., installation, upgrades, rollbacks) into Kubernetes-native logic. However, operators are a subset of controllers, much like how a square is a specific type of rectangle. This distinction is vital for understanding how to design and implement scalable solutions.
Developing custom controllers involves three steps:
kubectl
or tools like kubectl apply
to create the CRD schema.Tools like the Java Operator SDK simplify development by automatically converting POJOs into CRDs, while the Go Operator SDK provides a robust foundation for complex operators. For example, a controller might automatically update Pod image tags or trigger restarts based on configuration changes.
CRDs serve as the foundation for platform engineering, enabling the creation of self-service developer platforms. By defining CRDs for internal tools, organizations can abstract infrastructure complexity and provide developers with intuitive APIs. For instance, a CRD might model a Database
resource, allowing developers to request and manage databases through a unified interface. Operators then automate the provisioning and lifecycle management of these resources, ensuring consistency across clusters.
This approach aligns with the principles of platform-as-a-product, where CRDs act as the source of truth for platform domains. By combining CRDs with controllers, teams can build scalable, maintainable platforms that adapt to evolving requirements.
Kubernetes’ power lies in its ability to abstract infrastructure while remaining extensible through CRDs and controllers. By leveraging these tools, developers can build platforms that align with business needs, automate operations, and reduce friction in cloud-native workflows. Whether managing Kubernetes-native resources or external systems, the principles of reconciliation, abstraction, and extensibility remain central to modern platform engineering. Starting with simple controllers and gradually expanding to full operators provides a pragmatic path to mastering this ecosystem.