4. 自定义资源(CRD)设计:定义 API 类型、生成清单与验证规则
自定义资源(Custom Resource Definition, CRD)是 Kubernetes 扩展能力的核心。在 Operator SDK 中,CRD 的设计直接决定了控制器的数据模型与行为边界。本章将深入讲解如何通过 types.go 定义 API 类型、使用工具链生成 CRD 清单,以及如何为字段添加验证规则,确保资源声明的正确性与健壮性。
4.1 API 类型定义:types.go 的结构与规范
Operator SDK 使用 types.go 文件定义自定义资源的结构。该文件通常位于 api/<version>/ 目录下,包含三个核心部分:Spec(期望状态)、Status(实际状态)和 资源顶层结构。
关键原则:Spec 定义用户输入的“期望”,Status 定义控制器观测的“实际”。两者分离,避免控制器直接修改 Spec。
以下是一个资源配额分配策略的典型 types.go 示例:
package v1
import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:resource:path=resourcequotas,shortName=rq
type ResourceQuotaPolicy struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec ResourceQuotaPolicySpec `json:"spec,omitempty"`
Status ResourceQuotaPolicyStatus `json:"status,omitempty"`
}
type ResourceQuotaPolicySpec struct {
// +kubebuilder:validation:Required
// +kubebuilder:validation:Minimum=1
// +kubebuilder:validation:Maximum=100
Replicas int32 `json:"replicas"`
// +kubebuilder:validation:Optional
// +kubebuilder:default={"cpu": "500m", "memory": "256Mi"}
ResourceLimits corev1.ResourceList `json:"resourceLimits,omitempty"`
// +kubebuilder:validation:Enum=Strict;BestEffort;Burstable
AllocationMode string `json:"allocationMode"`
}
type ResourceQuotaPolicyStatus struct {
// +kubebuilder:validation:Optional
Conditions []metav1.Condition `json:"conditions,omitempty"`
// +kubebuilder:validation:Optional
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
}
4.2 字段标记与验证规则
Kubebuilder 标记(markers)是嵌入在代码注释中的指令,用于控制 CRD 生成行为。下表列出最常用的验证与约束标记:
| 标记 | 作用 | 示例 |
|---|---|---|
+kubebuilder:validation:Required |
标记字段为必填 | // +kubebuilder:validation:Required |
+kubebuilder:validation:Optional |
标记字段为可选 | // +kubebuilder:validation:Optional |
+kubebuilder:validation:Minimum |
设置数值最小值 | // +kubebuilder:validation:Minimum=1 |
+kubebuilder:validation:Maximum |
设置数值最大值 | // +kubebuilder:validation:Maximum=100 |
+kubebuilder:validation:Enum |
限制字段只能取指定枚举值 | // +kubebuilder:validation:Enum=Strict;BestEffort |
+kubebuilder:default |
设置字段默认值 | // +kubebuilder:default={"cpu":"500m"} |
+kubebuilder:validation:Pattern |
正则表达式校验字符串 | // +kubebuilder:validation:Pattern=`^[a-z]+$` |
实战建议:对于资源配额字段,优先使用
corev1.ResourceList 类型,它天然支持 Kubernetes 资源单位的校验(如 "500m"、"1Gi"),无需额外编写验证逻辑。
4.3 生成 CRD 清单
Operator SDK 提供 make generate 和 make manifests 命令,自动从 types.go 生成 CRD YAML 清单。执行流程如下:
- 生成 DeepCopy 方法:
make generate调用controller-gen object:headerFile="hack/boilerplate.go.txt",为每个资源类型生成DeepCopyInto和DeepCopyObject方法。 - 生成 CRD YAML:
make manifests调用controller-gen crd,输出到config/crd/bases/目录。 - 生成 RBAC 与 Webhook 配置:同时生成 ClusterRole、Webhook 等清单文件。
生成的 CRD 清单示例(简化):
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: resourcequotapolicies.example.com
spec:
group: example.com
names:
kind: ResourceQuotaPolicy
plural: resourcequotapolicies
shortNames:
- rq
scope: Namespaced
versions:
- name: v1
schema:
openAPIV3Schema:
properties:
spec:
properties:
replicas:
minimum: 1
maximum: 100
type: integer
allocationMode:
enum:
- Strict
- BestEffort
- Burstable
type: string
subresources:
status: {}
4.4 CRD 字段与验证规则设计流程
下图展示了从 types.go 定义到 CRD 清单生成的完整链路:
4.5 高级验证:Webhook 与 CEL
除了 CRD 内置的 OpenAPI v3 验证,Operator SDK 还支持两种更强大的验证方式:
- 准入 Webhook(ValidatingAdmissionWebhook):在资源创建或更新时执行自定义 Go 逻辑,适合跨字段校验或调用外部系统。
- CEL(Common Expression Language):Kubernetes 1.25+ 支持在 CRD 中直接嵌入 CEL 表达式,无需编写 Webhook 即可实现复杂校验。
CEL 示例(在 CRD 中直接定义):
x-kubernetes-validations:
- rule: "self.replicas <= self.maxReplicas"
message: "replicas 不能超过 maxReplicas"
- rule: "has(self.allocationMode) ? self.allocationMode in ['Strict','BestEffort'] : true"
message: "allocationMode 必须为 Strict 或 BestEffort"
注意:CEL 表达式在 CRD 级别生效,性能优于 Webhook,但无法调用外部 API。对于需要复杂业务逻辑的场景,仍应使用 ValidatingWebhook。
4.6 字段设计最佳实践
| 实践 | 说明 | 示例 |
|---|---|---|
| 使用强类型 | 避免使用 string 表示枚举,使用 Enum 标记 |
// +kubebuilder:validation:Enum=Strict;BestEffort |
| 设置合理默认值 | 减少用户输入负担,提升易用性 | // +kubebuilder:default={"cpu":"500m"} |
| 区分 Spec 与 Status | Spec 只读(用户设置),Status 只写(控制器更新) | Status 字段全部标记 Optional |
| 使用资源类型 | CPU/内存使用 corev1.ResourceList |
自动支持 "500m"、"1Gi" 格式 |
| 避免嵌套过深 | 嵌套超过 3 层影响可读性与校验性能 | 使用扁平结构 + 引用类型 |
4.7 验证规则冲突与调试
在 CRD 设计过程中,常见的验证规则冲突包括:
- Minimum 大于 Maximum:导致所有值均无法通过校验。
- Enum 与 Pattern 冲突:同时设置枚举和正则,可能导致无合法值。
- Required 与 Default 冲突:必填字段不应设置默认值,否则默认值会被忽略。
调试方法:使用 kubectl explain 查看 CRD 的 Schema 结构,或直接查看 config/crd/bases/ 下的 YAML 文件,确认生成的 OpenAPI 规则是否符合预期。
快速验证:执行
make manifests 后,使用 kubectl apply --dry-run=server -f config/samples/ 测试 CRD 实例的校验效果。