CRD 定义文件结构深度解析

自定义资源定义(CRD)是 Kubernetes 扩展机制的核心,它通过声明式 YAML 文件告诉 API Server 一种新的资源类型及其验证规则。理解 CRD YAML 的每一层结构,是编写可靠 Operator 的基础。本章将逐层拆解 CRD 定义文件的 apiVersion、kind、metadata、spec 四大核心字段,并深入 OpenAPI v3 Schema 验证规则。

CRD YAML 顶层结构概览

一个标准的 CRD 定义文件遵循 Kubernetes 资源模型,其顶层字段构成如下:

字段 必填 说明
apiVersion 是 CRD 资源本身的 API 版本,当前稳定版为 apiextensions.k8s.io/v1
kind 是 固定为 CustomResourceDefinition
metadata 是 资源元数据,包含 name(必须符合 DNS 子域名规范)
spec 是 CRD 的核心定义,包含 group、names、scope、versions 等
status 否 CRD 资源自身的状态,由 API Server 自动填充
关键提示: 从 Kubernetes 1.16 开始,apiextensions.k8s.io/v1 成为稳定版本,废弃了 v1beta1。生产环境必须使用 v1 版本,它强制要求 spec.preserveUnknownFields: false 并严格校验 OpenAPI v3 Schema。
CRD YAML 顶层结构树 CRD YAML 根 apiVersion kind metadata spec group names scope versions name / served storage schema 📌 核心层级 apiVersion → 版本声明 kind → 资源类型 spec → 定义主体

apiVersion 与 kind:资源身份声明

apiVersion 决定了 CRD 资源本身的 API 组和版本。当前稳定版必须使用:

apiVersion: apiextensions.k8s.io/v1

kind 固定为 CustomResourceDefinition,这是 Kubernetes 内置的资源类型,用于注册新的自定义资源。

版本兼容性警告: 如果集群版本低于 1.16,apiextensions.k8s.io/v1 不可用。但鉴于当前主流 Kubernetes 版本均已 >= 1.20,建议所有新 CRD 直接使用 v1 版本,避免后续迁移成本。

metadata.name:DNS 子域名规范

metadata.name 是 CRD 的唯一标识符,必须遵循 DNS 子域名规范(RFC 1123)。命名规则为:

  • 格式: <plural>.<group>
  • 示例: 如果定义 group: example.com,names.plural: myresources,则 name 必须为 myresources.example.com
  • 长度限制: 最多 253 个字符
  • 字符集: 仅允许小写字母、数字、连字符(-)和点(.)
metadata:
  name: myresources.example.com

spec 字段详解:CRD 的核心定义

spec 是 CRD 定义中最复杂的部分,它决定了自定义资源的行为和结构。下表列出了 spec 中的关键字段:

字段 类型 必填 说明
group string 是 API 组名称,如 stable.example.com
names object 是 包含 plural、singular、shortNames、kind、listKind
scope string 是 Namespaced 或 Cluster
versions []object 是 至少一个版本,每个版本包含 name、served、storage、schema
conversion object 否 版本转换策略(Webhook 或 None)
preserveUnknownFields boolean 否 v1 版本中必须为 false 或省略

names 对象:资源命名体系

names 字段定义了自定义资源在集群中的各种名称形式:

子字段 必填 示例 说明
plural 是 myresources 用于 kubectl get myresources
singular 否 myresource 用于 kubectl get myresource
shortNames 否 ["mr", "mrs"] 简短别名,如 kubectl get mr
kind 是 MyResource 资源类型名,用于 YAML 的 kind 字段
listKind 否 MyResourceList 列表类型名,默认 <kind>List

versions 数组:多版本管理

每个版本包含三个关键属性:

  • name: 版本名称,如 v1、v1beta1
  • served: 布尔值,表示该版本是否可通过 API 提供服务
  • storage: 布尔值,表示该版本是否用于持久化存储(每个 CRD 只能有一个 storage: true 的版本)
  • schema: OpenAPI v3 Schema 定义,描述资源字段结构
最佳实践: 始终将最新稳定版本设为 storage: true。如果存在多个版本,确保所有版本之间的数据可以通过 conversion 策略无损转换。

OpenAPI v3 Schema 验证规则

OpenAPI v3 Schema 是 CRD 定义中最关键的部分,它决定了自定义资源实例的字段结构、类型和验证规则。Schema 定义在 spec.versions[*].schema.openAPIV3Schema 下。

核心验证关键字

关键字 适用类型 说明
type 所有 字段类型:object、string、integer、number、boolean、array
properties object 定义对象的子字段
required object 必填字段列表
minimum / maximum number, integer 数值范围限制
minLength / maxLength string 字符串长度限制
pattern string 正则表达式匹配
enum 所有 枚举值列表
items array 数组元素的 Schema
additionalProperties object 是否允许额外字段(v1 中默认为 false)

完整 CRD 示例

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: myresources.stable.example.com
spec:
  group: stable.example.com
  names:
    plural: myresources
    singular: myresource
    shortNames:
    - mr
    kind: MyResource
    listKind: MyResourceList
  scope: Namespaced
  versions:
  - name: v1
    served: true
    storage: true
    schema:
      openAPIV3Schema:
        type: object
        properties:
          spec:
            type: object
            properties:
              replicas:
                type: integer
                minimum: 1
                maximum: 100
              image:
                type: string
                pattern: '^[a-z0-9]+/[a-z0-9]+:[a-z0-9]+$'
              enabled:
                type: boolean
              tags:
                type: array
                items:
                  type: string
                  maxLength: 20
            required:
            - replicas
            - image
          status:
            type: object
            properties:
              availableReplicas:
                type: integer
              conditions:
                type: array
                items:
                  type: object
                  properties:
                    type:
                      type: string
                    status:
                      type: string
                      enum:
                      - "True"
                      - "False"
                      - "Unknown"
                    lastTransitionTime:
                      type: string
                  required:
                  - type
                  - status
OpenAPI v3 Schema 验证流程 CR 实例 YAML 提交 API Server 接收请求 OpenAPI v3 Schema 验证 类型检查 / 必填字段 / 正则 / 枚举 / 范围 ❌ 拒绝请求 ✅ 写入 etcd 🔍 验证失败常见原因 类型不匹配 / 缺少必填字段 / 正则不通过

高级 Schema 技巧与避坑

常见陷阱: 在 apiextensions.k8s.io/v1 中,additionalProperties 默认为 false。这意味着如果 Schema 中未显式定义的字段,提交 CR 实例时会被拒绝。这与 v1beta1 的行为不同,迁移时务必检查所有字段是否已在 Schema 中声明。

x-kubernetes-* 扩展字段

Kubernetes 在 OpenAPI v3 基础上扩展了若干 x-kubernetes-* 前缀字段,用于实现更精细的控制:

扩展字段 说明
x-kubernetes-int-or-string 允许字段接受整数或字符串类型(如 port 字段)
x-kubernetes-preserve-unknown-fields 在对象中保留未在 Schema 中定义的字段
x-kubernetes-embedded-resource 标记字段为内嵌的 Kubernetes 资源对象
x-kubernetes-list-type 指定数组的合并策略:atomic、set、map
x-kubernetes-list-map-keys 当 list-type: map 时,指定作为 map key 的字段
# 使用 x-kubernetes-int-or-string 示例
properties:
  port:
    x-kubernetes-int-or-string: true
    # 允许 port: 8080 或 port: "8080"

Schema 定义最佳实践清单

  1. 始终定义 required 字段: 避免 Operator 处理空值导致的 panic
  2. 使用 enum 约束状态值: 如 status.phase 限定为 Pending、Running、Failed
  3. 为数值字段设置 minimum/maximum: 防止资源滥用
  4. 利用 pattern 验证字符串格式: 如镜像名称、DNS 标签
  5. 谨慎使用 x-kubernetes-preserve-unknown-fields: 它会绕过 Schema 验证,降低安全性
  6. 为 status 子资源单独定义 Schema: 确保 status 字段结构清晰
调试技巧: 使用 kubectl explain crd 查看 CRD 字段文档,或使用 kubectl get crd <name> -o yaml 查看已注册 CRD 的完整定义。对于 Schema 验证问题,API Server 会返回详细的 422 错误信息,包含具体字段路径和失败原因。