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 支持三类校验机制:

  1. OpenAPI 原生校验:pattern、minimum、maximum、minLength、maxLength、enum。
  2. x-kubernetes-* 扩展:x-kubernetes-int-or-string、x-kubernetes-embedded-resource、x-kubernetes-preserve-unknown-fields。
  3. 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 进行校验:

CRD Schema 校验流程 用户 / kubectl API Server OpenAPI v3 Schema 校验 etcd POST /apis/... 校验请求 写入 校验失败 → 拒绝 校验流程说明 1. 用户提交 CR → API Server 接收请求 2. API Server 根据 CRD 的 openAPIV3Schema 执行结构校验 3. 校验通过 → 写入 etcd;校验失败 → 返回 422 Unprocessable Entity

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 会随平台演进迭代。推荐采用多版本策略:

CRD Schema 版本演进策略 v1alpha1 实验性,字段可变更 v1alpha2 迭代,字段调整 v1beta1 Beta,字段稳定 v1 GA,字段不可变 转换 Webhook 处理版本转换
版本演进规则:
  • 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 行为。