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