1. CRD 基础概念

1.1 什么是 CustomResourceDefinition

CustomResourceDefinition(CRD)是 Kubernetes 内置的一种 API 资源类型,它允许用户在不修改核心 Kubernetes 源码的前提下,向集群中注册并管理自定义的资源类型。CRD 本质上是 Kubernetes API 的扩展机制,通过声明式配置定义新资源的名称、分组、版本和结构,Kubernetes 会为其自动生成 RESTful API 端点、存储(etcd)以及基础的 CRUD 操作。

核心定义:CRD 是一个 API 资源,它定义了“如何定义一个新的 API 资源”。一旦创建 CRD,用户就可以像操作 Pod、Deployment 一样,通过 kubectl 或 API 调用来创建、查询、更新和删除该自定义资源的实例。

以下是一个典型的 CRD 定义示例,它定义了一个名为 Application 的自定义资源:

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: applications.example.com
spec:
  group: example.com
  names:
    kind: Application
    plural: applications
    singular: application
    shortNames:
      - app
  scope: Namespaced
  versions:
    - name: v1
      served: true
      storage: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                replicas:
                  type: integer
                image:
                  type: string
            status:
              type: object
              properties:
                availableReplicas:
                  type: integer
                phase:
                  type: string
字段 说明 示例值
spec.group API 组,用于资源分组和隔离 example.com
spec.names.kind 资源类型名称,用于 YAML 中的 kind 字段 Application
spec.names.plural 复数名称,用于 API 路径和 kubectl 命令 applications
spec.scope 资源作用域:Namespaced 或 Cluster Namespaced
spec.versions[].schema OpenAPI v3 Schema,定义资源字段结构和校验规则 JSON Schema 对象
CRD 定义与实例化流程 用户/管理员 CRD 定义 applications.example.com Kubernetes API Server 自动注册 RESTful API /apis/example.com/v1/ etcd 持久化存储 创建实例 Application 实例 my-app (v1) 关键流程说明: 1. 用户提交 CRD YAML → API Server 校验并存储到 etcd 2. API Server 自动生成 RESTful 端点,支持 CRUD 操作 3. 用户提交自定义资源实例 → 按 CRD 定义的 Schema 校验并存储

1.2 CRD 与原生资源的关系

CRD 定义的自定义资源与 Kubernetes 原生资源(如 Pod、Service、Deployment)在 API 机制上完全对等,但在实现深度上存在本质差异。下表从多个维度对比两者的关系:

对比维度 原生资源(Pod/Deployment 等) CRD 自定义资源
API 机制 内置在 API Server 中,代码级实现 通过 CRD 声明式注册,API Server 自动生成端点
存储 存储在 etcd,由 API Server 管理 存储在 etcd,由 API Server 管理(完全一致)
校验 内置 Go 代码校验 + 准入 Webhook OpenAPI v3 Schema 校验 + 可选准入 Webhook
默认控制器 有(kube-controller-manager 内置) 无,需要用户自行开发 Operator 或控制器
状态管理 控制器自动更新 status 字段 需要 Operator 手动更新 status 子资源
垃圾回收 支持 OwnerReference 级联删除 支持 OwnerReference 级联删除(机制相同)
版本管理 内置多版本转换 需配置 conversion Webhook 或指定 storage 版本
关键理解:CRD 让自定义资源在“数据平面”(API、存储、校验)上与原生资源平起平坐,但在“控制平面”(控制器、状态管理、默认行为)上需要用户自行补齐。这也是 Operator 模式存在的根本原因——Operator 就是自定义资源的控制器。

1.3 CRD 在 Kubernetes 生态中的角色

CRD 是 Kubernetes 生态扩展能力的基石,它使得 Kubernetes 从一个容器编排平台演变为一个通用的云原生应用平台。CRD 在生态中扮演以下核心角色:

  • 平台扩展层:CRD 允许平台团队定义业务领域模型(如 Database、Certificate、Pipeline),将 Kubernetes 从“资源调度层”提升为“业务抽象层”。
  • Operator 模式的基础:几乎所有 Operator(如 etcd-operator、prometheus-operator、cert-manager)都依赖 CRD 定义其管理的资源类型,CRD 是 Operator 的“数据模型”。
  • 声明式配置的载体:CRD 实例以 YAML/JSON 形式存在,天然适配 GitOps 工作流,支持版本控制、审计和自动化运维。
  • 生态互操作的契约:不同项目通过 CRD 暴露其 API,例如 Istio 的 VirtualService、Knative 的 Service,CRD 成为生态组件之间的标准化接口。
CRD 在 Kubernetes 生态中的角色 CustomResource Definition (CRD) 平台扩展层 业务领域模型抽象 Operator 模式基础 控制器 + 自定义资源 声明式配置载体 GitOps / 版本控制 生态互操作契约 标准化 API 接口 生态示例: Istio (VirtualService/DestinationRule) · cert-manager (Certificate/Issuer) · Prometheus Operator (ServiceMonitor/PrometheusRule) · Knative (Service/Configuration)
常见误区:CRD 不等于 Operator。CRD 只定义了“数据模型”,而 Operator 是“控制逻辑”。没有 Operator 的 CRD 只能作为静态配置存储,无法实现自动化编排和状态修复。在故障排查时,80% 的问题出在 Operator 逻辑而非 CRD 定义本身。

1.4 CRD 的生命周期与版本管理

CRD 本身也是一种 API 资源,拥有完整的生命周期管理能力。理解 CRD 的生命周期对于 Operator 开发和故障排查至关重要:

  1. 创建阶段:提交 CRD YAML 到集群,API Server 校验 Schema 合法性,注册新的 RESTful 端点。
  2. 版本演进:CRD 支持多个版本共存(如 v1alpha1、v1beta1、v1),通过 spec.versions 定义。每个版本可以独立定义 Schema,但只有一个版本被标记为 storage: true。
  3. 废弃与删除:删除 CRD 会级联删除所有自定义资源实例(除非设置了 preserveUnknownFields)。建议先移除所有实例再删除 CRD。
阶段 操作 注意事项
创建 kubectl apply -f crd.yaml 确保 group 和 kind 不与其他 CRD 冲突;Schema 必须合法
更新 kubectl apply -f crd-v2.yaml Schema 变更必须向后兼容;已存储的实例不会自动迁移
版本转换 配置 conversion Webhook 或手动迁移 不配置 conversion 时,只能通过 storage 版本读写
删除 kubectl delete crd applications.example.com 会删除所有关联的自定义资源实例,操作不可逆
最佳实践:在生产环境中,CRD 的 Schema 变更应遵循“先增后删”原则。新增字段时设置 default 或 nullable: true,避免已存储的旧实例因缺少字段而校验失败。对于破坏性变更,建议创建新版本的 CRD 并逐步迁移。