4. CRD Schema 设计:OpenAPI v3 Schema、required/type/properties 定义、validation 规则编写
CRD(Custom Resource Definition)的 Schema 是控制面的“数据契约”。Kubernetes 从 1.16 起强制使用 structural schema,底层基于 OpenAPI v3.0。本章聚焦如何编写一个既满足平台扩展需求、又通过 API Server 校验的 Schema。
4.1 OpenAPI v3 Schema 在 CRD 中的角色
CRD 的 openAPIV3Schema 字段定义了自定义资源的“形状”和“约束”。API Server 在写入 etcd 前会执行声明式校验,拒绝不符合 Schema 的请求。
| 维度 | 说明 | 示例 |
|---|---|---|
| 类型约束 | 字段必须为指定类型(string、integer、object、array 等) | type: string |
| 必填校验 | required 列表中的字段在创建时必须存在 | required: ["name", "spec"] |
| 属性定义 | properties 描述每个子字段的 schema | properties.replicas.type: integer |
| 高级校验 | pattern、minimum、maximum、enum、x-kubernetes-* 扩展 | pattern: "^[a-z]+$" |
设计原则:Schema 应足够严格以捕获配置错误,但也要为未来扩展预留空间。推荐将“平台内部字段”与“用户可见字段”分层定义。
4.2 核心结构:type、properties、required
一个典型的 CRD Schema 遵循以下骨架:
openAPIV3Schema:
type: object
required:
- spec
properties:
spec:
type: object
required:
- functionName
- runtime
properties:
functionName:
type: string
pattern: '^[a-z0-9]([a-z0-9-]*[a-z0-9])?$'
maxLength: 63
runtime:
type: string
enum:
- python3.9
- nodejs18
- go1.21
replicas:
type: integer
minimum: 0
maximum: 100
default: 1
env:
type: array
items:
type: object
required:
- name
properties:
name:
type: string
pattern: '^[A-Z_][A-Z0-9_]*$'
value:
type: string
status:
type: object
properties:
phase:
type: string
enum:
- Pending
- Running
- Failed
lastHeartbeatTime:
type: string
format: date-time
关键点:
required只在type: object下有效,用于声明哪些属性必须存在。default字段在 CRD v1 中支持,API Server 会在创建时自动填充。format用于语义化类型(如date-time、int-or-string)。
4.3 Validation 规则编写:从基础到高级
Kubernetes 支持三类校验机制:
- OpenAPI 原生校验:pattern、minimum、maximum、minLength、maxLength、enum。
- x-kubernetes-* 扩展:
x-kubernetes-int-or-string、x-kubernetes-embedded-resource、x-kubernetes-preserve-unknown-fields。 - CRD 转换 Webhook:用于跨版本校验或复杂业务逻辑(第 6 章详述)。
以下表格列出最常用的校验规则及其适用场景:
| 规则 | 类型 | 示例值 | 说明 |
|---|---|---|---|
pattern |
string | ^[a-z0-9-]+$ |
正则表达式匹配,常用于名称校验 |
minimum / maximum |
integer / number | minimum: 1, maximum: 100 |
数值范围约束 |
minLength / maxLength |
string | maxLength: 253 |
字符串长度限制 |
enum |
任意 | ["small", "medium", "large"] |
枚举值白名单 |
minItems / maxItems |
array | maxItems: 10 |
数组元素个数限制 |
uniqueItems |
array | true |
数组元素必须唯一 |
x-kubernetes-int-or-string |
特殊 | true |
字段可接受 integer 或 string |
x-kubernetes-preserve-unknown-fields |
特殊 | true |
允许未知字段通过,用于灵活扩展 |
避坑提示:
- 不要对
status子资源设置required或default,status 由控制器管理,用户不应直接写入。 pattern使用 RE2 语法,不支持回溯引用和负向前瞻。- 使用
x-kubernetes-preserve-unknown-fields会绕过结构校验,仅在确实需要动态字段时使用。
4.4 从 Schema 到控制面校验流程
下图展示了用户提交 CR 后,API Server 如何利用 Schema 进行校验:
4.5 实战:Serverless Function CRD Schema 设计
以 Serverless 平台中的 Function 资源为例,展示完整的 Schema 设计:
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: functions.serverless.example.com
spec:
group: serverless.example.com
names:
kind: Function
plural: functions
singular: function
shortNames:
- fn
scope: Namespaced
versions:
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required:
- spec
properties:
spec:
type: object
required:
- image
- runtime
properties:
image:
type: string
pattern: '^[a-z0-9]+(?:[._-][a-z0-9]+)*(/[a-z0-9]+(?:[._-][a-z0-9]+)*)*(:[a-zA-Z0-9._-]+)?$'
maxLength: 256
runtime:
type: string
enum:
- python3.9
- nodejs18
- go1.21
- java17
replicas:
type: integer
minimum: 0
maximum: 200
default: 1
timeout:
type: integer
minimum: 1
maximum: 900
default: 60
env:
type: array
items:
type: object
required:
- name
properties:
name:
type: string
pattern: '^[A-Z_][A-Z0-9_]*$'
maxLength: 253
value:
type: string
maxLength: 65536
x-kubernetes-list-type: map
x-kubernetes-list-map-keys:
- name
resources:
type: object
properties:
cpu:
type: string
pattern: '^[0-9]+m?$'
memory:
type: string
pattern: '^[0-9]+(Ki|Mi|Gi)?$'
status:
type: object
properties:
phase:
type: string
enum:
- Pending
- Deploying
- Running
- Scaling
- Failed
observedGeneration:
type: integer
format: int64
conditions:
type: array
items:
type: object
required:
- type
- status
properties:
type:
type: string
status:
type: string
enum:
- "True"
- "False"
- "Unknown"
reason:
type: string
message:
type: string
lastTransitionTime:
type: string
format: date-time
x-kubernetes-list-type: atomic
lastHeartbeatTime:
type: string
format: date-time
Schema 设计要点:
- required 分层:顶层只要求
spec,spec 内部要求image和runtime,其余字段有默认值。 - enum 约束:runtime 和 phase 使用枚举,避免非法值。
- x-kubernetes-list-type:
map类型确保 env 按 name 去重;atomic类型确保 conditions 整体替换。 - pattern 校验:image 和 env.name 使用正则,防止注入和格式错误。
4.6 高级校验:x-kubernetes-validations (CEL)
Kubernetes 1.25+ 支持使用 Common Expression Language (CEL) 编写声明式校验规则,适用于跨字段校验和复杂逻辑。
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
minReplicas:
type: integer
maxReplicas:
type: integer
x-kubernetes-validations:
- rule: "self.minReplicas <= self.maxReplicas"
message: "minReplicas must be less than or equal to maxReplicas"
- rule: "self.minReplicas >= 0"
message: "minReplicas must be non-negative"
| 特性 | 说明 | 示例 |
|---|---|---|
| rule | CEL 表达式,返回布尔值 | self.replicas <= self.maxReplicas |
| message | 校验失败时返回的错误信息 | "replicas 不能超过 maxReplicas" |
| messageExpression | 动态生成错误信息(1.28+) | "'replicas ' + string(self.replicas) + ' 超出范围'" |
| reason | 可选,指定失败原因类型 | FieldValueInvalid |
最佳实践:优先使用 OpenAPI 原生校验(pattern、minimum、enum),性能更好;CEL 用于跨字段依赖或动态条件校验。避免在 CEL 中执行 IO 操作或复杂循环。
4.7 Schema 版本管理:从 v1alpha1 到 v1
CRD Schema 会随平台演进迭代。推荐采用多版本策略:
版本演进规则:
- v1alphaX:字段可增删改,不保证向后兼容。
- v1beta1:字段可增不可删,弃用字段使用
// Deprecated注释。 - v1:字段不可变,移除所有 alpha/beta 字段,提供转换 Webhook。
- 始终使用
storage: true标记存储版本,其他版本通过转换 Webhook 实现读写兼容。
4.8 常见 Schema 设计错误与修复
| 错误模式 | 现象 | 修复方案 |
|---|---|---|
缺少 required 字段 |
用户提交空 spec,控制器 panic | 在 spec 层添加 required: ["image", "runtime"] |
| enum 值大小写不一致 | 校验通过但控制器无法识别 | 统一使用小写枚举值,如 python3.9 |
| pattern 过于宽松 | 允许包含特殊字符,导致下游错误 | 使用 ^[a-z0-9]([a-z0-9-]*[a-z0-9])?$ 限制名称 |
未设置 x-kubernetes-list-type |
数组字段无法正确合并 | 根据语义选择 map、set 或 atomic |
status 包含 required |
控制器无法更新 status | status 子资源不应设置 required |
生产建议:在提交 CRD 到集群前,使用
kubectl apply --dry-run=server 验证 Schema 合法性。同时建议编写单元测试,使用 k8s.io/apiextensions-apiserver 的校验工具模拟 API Server 行为。