CRD Operator控制器开发与状态调试 - 第2节
2.1 自定义资源定义(CRD)详解
自定义资源定义(Custom Resource Definition,CRD)是 Kubernetes 扩展机制的核心,它允许你在集群中定义全新的资源类型,就像内置的 Pod、Service 一样。CRD 本身是一个 API 资源,通过声明式配置告诉 Kubernetes API Server 新的资源结构。
2.1.1 CRD 的核心结构
一个标准的 CRD 定义包含以下关键字段:
| 字段 | 类型 | 说明 |
|---|---|---|
apiVersion |
string | 固定为 apiextensions.k8s.io/v1 |
kind |
string | 固定为 CustomResourceDefinition |
metadata.name |
string | 必须匹配 spec.names.plural + "." + spec.group |
spec.group |
string | API 组名称,如 example.com |
spec.names |
object | 资源名称定义(plural、singular、kind、shortNames) |
spec.scope |
string | Namespaced 或 Cluster |
spec.versions |
array | 版本列表,每个版本包含 schema、subresources 等 |
调试要点: CRD 的
metadata.name 必须严格遵循 {plural}.{group} 格式,否则 API Server 会拒绝创建。这是 Operator 调试中最常见的配置错误之一。
2.1.2 CRD 版本管理机制
Kubernetes 1.16+ 支持 CRD 的多版本管理,允许同时维护多个 API 版本,并通过转换机制实现数据兼容。版本管理涉及三个核心概念:
- 存储版本(storage version):集群中实际持久化存储的版本,每个 CRD 只能指定一个存储版本。
- 服务版本(served version):API Server 对外提供访问的版本,可以同时启用多个。
- 版本转换(conversion):不同版本之间的数据转换策略,支持 Webhook 转换或 None(字段名完全一致)。
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: databases.example.com
spec:
group: example.com
names:
kind: Database
plural: databases
singular: database
shortNames:
- db
scope: Namespaced
versions:
- name: v1alpha1
served: true
storage: false
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
engine:
type: string
version:
type: string
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
engine:
type: string
version:
type: string
replicas:
type: integer
subresources:
status: {}
调试技巧: 当 CRD 包含多个版本时,使用
kubectl get crd databases.example.com -o yaml 查看 status.storedVersions 字段,确认当前集群中实际存储了哪些版本的数据。如果存储版本列表异常,可能导致资源无法正常读取。
2.2 自定义资源(CR)实例
自定义资源(Custom Resource,CR)是 CRD 的具体实例化对象,类似于 Pod 是 PodTemplate 的实例。CR 遵循标准的 Kubernetes 资源格式,包含 apiVersion、kind、metadata 和 spec 等核心字段。
2.2.1 CR 实例的结构与创建
以下是一个基于上述 CRD 的 CR 实例:
apiVersion: example.com/v1
kind: Database
metadata:
name: my-production-db
namespace: default
spec:
engine: postgresql
version: "14.5"
replicas: 3
创建 CR 实例后,Kubernetes API Server 会执行以下流程:
- 验证 CR 的 apiVersion 和 kind 是否匹配已注册的 CRD。
- 根据 CRD 中定义的 OpenAPI Schema 校验 CR 的字段结构。
- 将 CR 对象持久化到 etcd 中。
- 触发对应的 Watch 事件,通知正在监听的 Controller。
常见调试陷阱: CR 的
apiVersion 格式为 {group}/{version},而不是 {group}:{version}。例如 example.com/v1 正确,example.com:v1 会导致 API Server 返回 404 错误。
2.2.2 CR 与内置资源的差异
| 对比维度 | 内置资源(如 Pod) | 自定义资源(CR) |
|---|---|---|
| 定义方式 | Kubernetes 源码内置 | 通过 CRD 动态注册 |
| Schema 校验 | 硬编码在 API Server 中 | 通过 OpenAPI v3 Schema 声明 |
| 默认控制器 | kube-controller-manager 内置 | 需要自定义 Operator 实现 |
| 子资源 | 默认支持 status、scale | 需在 CRD 中显式声明 |
| 版本升级 | 随 Kubernetes 版本升级 | 通过 CRD 版本管理独立演进 |
2.3 CRD 版本管理实战
2.3.1 版本转换策略
当 CRD 存在多个服务版本时,API Server 需要在不同版本之间转换数据。Kubernetes 提供两种转换策略:
- None 转换:要求所有版本的字段结构完全一致,API Server 直接复制数据,无需额外转换逻辑。
- Webhook 转换:通过自定义转换 Webhook 实现复杂的字段映射和逻辑转换,适用于版本间数据结构差异较大的场景。
调试建议: 在 Operator 开发初期,建议使用 None 转换策略,减少调试复杂度。当需要引入破坏性变更时,再切换到 Webhook 转换。使用
kubectl convert 命令可以测试 CR 实例在不同版本之间的转换结果。
2.3.2 版本迁移与数据一致性
版本迁移是 CRD 版本管理中最容易出问题的环节。以下是一个典型的版本迁移流程:
- 在 CRD 中添加新版本,设置
storage: false,保留旧版本为存储版本。 - 逐步更新所有 CR 实例的
apiVersion字段,使其指向新版本。 - 验证所有 CR 实例在新版本下读写正常。
- 修改 CRD,将新版本设为
storage: true,旧版本设为storage: false。 - 触发存储版本迁移(通过更新 CR 实例或使用存储版本迁移工具)。
- 确认 etcd 中所有数据已迁移到新版本后,移除旧版本。
关键调试点: 存储版本迁移后,旧版本的 CR 实例仍然可以通过 API 读取,但 etcd 中实际存储的是新版本数据。如果迁移过程中出现数据损坏,可以使用
kubectl get crd <name> -o jsonpath='{.status.storedVersions}' 检查存储版本列表是否异常。
2.4 CRD 调试常用命令
在 Operator 开发过程中,掌握以下调试命令可以快速定位 CRD 相关问题:
| 命令 | 用途 | 调试场景 |
|---|---|---|
kubectl get crd |
列出所有 CRD | 确认 CRD 是否已注册 |
kubectl describe crd <name> |
查看 CRD 详细信息 | 检查版本配置、子资源声明 |
kubectl get <resource> --v=8 |
查看 API 请求详情 | 调试 CR 创建/更新失败原因 |
kubectl convert -f cr.yaml --output-version example.com/v1 |
测试版本转换 | 验证不同版本间的字段映射 |
kubectl get crd <name> -o jsonpath='{.status.storedVersions}' |
查看存储版本列表 | 检查版本迁移是否完成 |
调试效率提升: 使用
kubectl api-resources --api-group=example.com 可以快速查看当前集群中属于特定 API 组的所有自定义资源类型,避免手动查找 CRD 名称。