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 会执行以下流程:

  1. 验证 CR 的 apiVersion 和 kind 是否匹配已注册的 CRD。
  2. 根据 CRD 中定义的 OpenAPI Schema 校验 CR 的字段结构。
  3. 将 CR 对象持久化到 etcd 中。
  4. 触发对应的 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 版本管理中最容易出问题的环节。以下是一个典型的版本迁移流程:

  1. 在 CRD 中添加新版本,设置 storage: false,保留旧版本为存储版本。
  2. 逐步更新所有 CR 实例的 apiVersion 字段,使其指向新版本。
  3. 验证所有 CR 实例在新版本下读写正常。
  4. 修改 CRD,将新版本设为 storage: true,旧版本设为 storage: false。
  5. 触发存储版本迁移(通过更新 CR 实例或使用存储版本迁移工具)。
  6. 确认 etcd 中所有数据已迁移到新版本后,移除旧版本。
关键调试点: 存储版本迁移后,旧版本的 CR 实例仍然可以通过 API 读取,但 etcd 中实际存储的是新版本数据。如果迁移过程中出现数据损坏,可以使用 kubectl get crd <name> -o jsonpath='{.status.storedVersions}' 检查存储版本列表是否异常。
CRD 版本管理架构图 CRD 定义 group: example.com kind: Database versions: v1alpha1 (served) v1 (served + storage) CR 实例 apiVersion: example.com/v1 kind: Database metadata.name: my-db spec.engine: postgresql spec.replicas: 3 API Server ① 版本匹配 ② Schema 校验 ③ 版本转换 ④ etcd 持久化 etcd 存储 存储版本: v1 版本转换策略 • None 转换:所有版本字段结构完全一致,API Server 直接复制数据 • Webhook 转换:通过自定义 Webhook 实现字段映射和逻辑转换 • 存储版本迁移:修改 CRD 的 storage 字段后,需要触发数据重写

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 名称。