Kubernetes CRD(自定义资源,CustomResourceDefinition)详解

Kubernetes CRD(自定义资源,CustomResourceDefinition)详解

文章目录

  • [Kubernetes CRD(自定义资源,CustomResourceDefinition)详解](#Kubernetes CRD(自定义资源,CustomResourceDefinition)详解)
    • [1. 引言](#1. 引言)
    • [2. 基本概念](#2. 基本概念)
    • [3. CRD 的工作原理](#3. CRD 的工作原理)
    • [4. 如何创建 CRD](#4. 如何创建 CRD)
    • [5. 使用 CRD](#5. 使用 CRD)
    • [6. 控制器模式](#6. 控制器模式)
    • [7. 高级特性](#7. 高级特性)
      • [7.1 版本管理](#7.1 版本管理)
      • [7.2 子资源](#7.2 子资源)
      • [7.3 验证和默认值](#7.3 验证和默认值)
      • [7.4 附加打印列](#7.4 附加打印列)
      • [7.5 最终确定器 (Finalizers)](#7.5 最终确定器 (Finalizers))
    • [8. 实际应用场景](#8. 实际应用场景)
    • [9. 最佳实践和注意事项](#9. 最佳实践和注意事项)
    • [10. 总结](#10. 总结)

1. 引言

Kubernetes 是一个可扩展的平台,其核心 API 提供了诸如 Pod、Service、Deployment 等丰富的内置资源,用于管理容器化应用。然而,在实际业务中,我们往往需要表达一些 Kubernetes 原生不支持的领域概念,例如数据库实例、消息队列主题、应用配置策略等。CustomResourceDefinition (CRD) 正是 Kubernetes 提供的一种机制,允许用户在不修改核心代码的情况下,向 Kubernetes API 中添加自定义的资源类型,从而将 Kubernetes 打造成一个通用的、可编程的应用平台。

CRD 是 Kubernetes API 扩展的事实标准,与 Operator 模式紧密结合,成为构建云原生基础设施和应用的关键技术。

2. 基本概念

CRD 本身是 Kubernetes API 中的一个内置资源类型(位于 apiextensions.k8s.io/v1 API 组)。通过创建一个 CRD 对象,你向 Kubernetes 声明了一种新的、用户自定义的资源类型。此后,你就可以像操作 Pod 一样,通过 kubectl 或直接调用 API 来创建、查看、更新和删除这种新资源的实例。

  • CustomResourceDefinition (CRD):定义一种新的资源类型的元数据,包括资源名称、API 组、版本、作用域(Namespaced 或 Cluster)以及结构验证规则等。
  • Custom Resource (CR):根据 CRD 定义创建出来的具体资源对象,代表某个领域实体的实例。

例如,你可以定义一个名为 Database 的 CRD,然后创建 database-sample 这样的 CR 来代表一个具体的数据库实例。

3. CRD 的工作原理

CRD 的实现基于 Kubernetes API 服务器的扩展能力。当你创建一个 CRD 对象时,API Server 会自动注册一个新的 RESTful 路径,用于处理该自定义资源的请求。其工作流程大致如下:

  1. 用户创建 CRD:用户提交一个 CRD YAML 到 Kubernetes API。
  2. API Server 动态注册 :API Server 解析 CRD,验证其合法性,然后在内部存储中注册新的资源类型。这相当于在 API Server 的路由表中增加了一条规则,将 /<api-group>/<version>/namespaces/<namespace>/<resource-plural> 路径映射到新的资源处理逻辑。
  3. 存储支持:自定义资源的数据同样存储在 etcd 中,与内置资源一样享受高可用和一致性保证。API Server 负责对 CR 进行请求认证、鉴权、验证(根据 CRD 中定义的 OpenAPI schema)以及持久化。
  4. 用户操作 CR :此后,用户可以通过标准的 Kubernetes API 或 kubectl 来操作自定义资源。例如 kubectl get databases 或 kubectl describe database database-sample。
  5. 控制器协调:通常,CRD 会配合一个控制器(Controller)一起工作。控制器监听自定义资源的变化,并根据 CR 的期望状态(Spec)执行相应的业务逻辑,最终更新资源的状态(Status)。这一模式正是 Kubernetes 声明式 API 的精髓。

4. 如何创建 CRD

创建一个 CRD 需要编写 YAML 清单,并通过 kubectl apply 提交。以下是一个简化的 CRD 示例,定义了一个名为 Database 的自定义资源:

yaml 复制代码
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: databases.example.com    必须格式:<plural>.<group>
spec:
  group: example.com              API 组
  versions:
    - name: v1alpha1              版本
      served: true                 是否在该版本上提供服务
      storage: true                是否将数据存储为该版本
      schema:                      OpenAPI v3 验证 schema
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                engine:
                  type: string
                  enum: ["mysql", "postgres"]
                version:
                  type: string
                storageGB:
                  type: integer
                  minimum: 1
            status:
              type: object
              properties:
                phase:
                  type: string
                connectionString:
                  type: string
      subresources:
        status: {}                  启用 status 子资源
        scale:                      启用 scale 子资源(可选)
          specReplicasPath: .spec.replicas
          statusReplicasPath: .status.replicas
      additionalPrinterColumns:     定义 `kubectl get` 显示的额外列
        - name: Engine
          type: string
          jsonPath: .spec.engine
        - name: Version
          type: string
          jsonPath: .spec.version
        - name: Age
          type: date
          jsonPath: .metadata.creationTimestamp
  scope: Namespaced                 作用域:Namespaced 或 Cluster
  names:
    plural: databases               复数名称,用于 URL
    singular: database              单数名称,用于 CLI 别名
    kind: Database                  资源类型名称,用于 YAML/CLI
    shortNames:                     短名称
      - db

关键字段说明:

  • group:自定义资源所属的 API 组,通常采用域名形式以避免冲突。
  • versions:支持一个或多个版本,每个版本可以独立定义验证 schema、子资源等。必须指定一个存储版本。
  • schema:OpenAPI v3 schema,用于验证自定义资源的字段类型和值,确保数据的合法性。强烈建议提供,避免无效数据进入 etcd。
  • subresources:启用 /status 和 /scale 子路径,方便控制器更新状态或水平伸缩。
  • additionalPrinterColumns:定义 kubectl get 输出时显示的额外列,提升可读性。
  • scope:资源是命名空间级别(Namespaced)还是集群级别(Cluster)。
  • names:资源的各种名称形式。

5. 使用 CRD

一旦 CRD 创建成功,你就可以像操作内置资源一样操作自定义资源。

  • 创建自定义资源实例(CR):

    yaml 复制代码
    apiVersion: example.com/v1alpha1
    kind: Database
    metadata:
      name: mydb
      namespace: default
    spec:
      engine: postgres
      version: "13"
      storageGB: 100

    使用 kubectl apply -f database.yaml 创建。

  • 查看自定义资源:

    bash 复制代码
    kubectl get databases
    kubectl get db           使用短名称
    kubectl describe database mydb
  • 直接访问 API :

    也可以通过 API Server 的代理访问,例如:

    bash 复制代码
    kubectl proxy --port=8080 &
    curl http://localhost:8080/apis/example.com/v1alpha1/namespaces/default/databases/mydb

6. 控制器模式

CRD 本身只负责存储和提供 API,而实际的业务逻辑需要通过控制器来实现。控制器监听自定义资源的事件(创建、更新、删除),然后采取相应的动作使实际状态趋近于期望状态。这种模式被称为 Operator 模式。

例如,一个 Database 控制器可能会:

  • 当发现一个新的 Database CR 时,根据 spec 中的引擎和版本信息,在底层云平台或数据库服务中创建一个真实的数据库实例。
  • 更新 CR 的 status 字段,将数据库的连接地址、状态等信息写回。
  • 当 CR 被删除时,清理对应的真实数据库资源。

开发控制器常用的工具包括:

  • kubebuilder:官方脚手架,基于 controller-runtime 库。
  • Operator SDK:由 Red Hat 主导,封装了 kubebuilder 并提供额外功能。
  • controller-runtime:直接使用 Go 库编写控制器。

7. 高级特性

7.1 版本管理

CRD 支持多个 API 版本共存,方便资源演进。你可以定义多个版本,并通过 storage 字段指定哪个版本负责存储。对于不同版本之间的转换,可以通过 Conversion Webhook 实现自定义的转换逻辑,确保旧版本对象可以无损地转换为新版本。

7.2 子资源

  • status 子资源 :启用后,对 CR 的 /status 子路径的更新不会触发 metadata.generation 的增加,便于控制器与用户更改分离。
  • scale 子资源 :使自定义资源可以接入 kubectl scale 命令,并与 HorizontalPodAutoscaler 集成。

7.3 验证和默认值

除了 OpenAPI schema 验证,CRD 还支持通过 ValidatingAdmissionWebhook 和 MutatingAdmissionWebhook 实现更复杂的验证和默认值设置。Webhook 可以在资源持久化之前拦截请求,进行自定义逻辑。

7.4 附加打印列

通过 additionalPrinterColumns,你可以让 kubectl get 的输出包含用户关心的字段,如状态、版本等,提升 CLI 的友好度。

7.5 最终确定器 (Finalizers)

与内置资源一样,CR 可以包含 finalizers,用于在删除资源前执行异步清理任务。控制器在完成清理后移除 finalizer,资源才会被真正删除。

8. 实际应用场景

CRD 广泛应用于云原生生态中的各种 Operator 和扩展:

  • Istio :通过 VirtualService、DestinationRule 等 CRD 管理服务网格流量规则。
  • Cert-Manager :提供 Certificate、Issuer 等 CRD 自动化 TLS 证书的申请和续期。
  • Prometheus Operator :使用 ServiceMonitor、PrometheusRule 等 CRD 动态配置监控和告警。
  • Knative :定义 Service、Revision 等 CRD 实现 Serverless 平台。
  • 数据库 Operator :如 MySQL Operator、Postgres Operator 通过 CRD 管理数据库实例的生命周期。

9. 最佳实践和注意事项

  • 设计良好的 API :遵循 Kubernetes API 设计规范,使用 spec 和 status 分离期望状态和实际状态。
  • 版本规划:从一开始考虑 API 的演进,合理设计多版本策略,尽早定义转换 webhook。
  • 提供完整的验证 schema:避免无效数据进入存储,减少控制器处理异常情况的复杂度。
  • 使用 status 子资源:让控制器通过 status 更新状态,避免与用户对 spec 的更新冲突。
  • 合理设置 finalizers:确保资源删除时能正确清理外部依赖,防止残留。
  • 注意性能:CRD 本身不会带来明显的性能开销,但大量 CR 或频繁的更新可能会增加 API Server 和 etcd 的压力。使用 label 选择器和 informer 机制减少不必要的监听。
  • 避免名称冲突 :选择特定的 API 组(如 company.com)以避免与其他 CRD 冲突。
  • 权限管理:使用 RBAC 为不同的用户或控制器授予对自定义资源的适当权限。

10. 总结

CRD 是 Kubernetes 可扩展性的基石,它允许你将 Kubernetes 的声明式 API 模型应用到任何领域。通过 CRD,用户可以定义自己的资源类型,并配合控制器实现复杂的自动化运维逻辑,即 Operator 模式。掌握 CRD 的设计与开发,能够帮助你充分利用 Kubernetes 平台的能力,构建高度自动化和可扩展的云原生应用。

无论是平台工程师还是应用开发者,理解 CRD 的工作原理和使用方法,都是在 Kubernetes 生态中进行深度实践的关键一步。

相关推荐
还卿一钵无情泪9 小时前
Docker 部署Unsloth 绕开环境配置难题
运维·人工智能·docker·ai·容器·nlp·干货
打工仔折腾 AI10 小时前
Docker镜像分层与卷挂载到底怎么工作:一次文件系统层面的实测分析
运维·人工智能·后端·python·docker·容器·性能优化
极客先躯12 小时前
高级java每日一道面试题-2026年01月20日-实战篇[Docker]-如何实现镜像的跨区域复制?
java·运维·docker·容器·架构图
dawnsky.liu12 小时前
OpenShift - 实现系统负载和业务负载分区隔离
kubernetes·openshift
杀不死的坏蛋c15 小时前
k8s-原理-网络-安装
kubernetes
紫神16 小时前
DDS 通信技术说明
网络·云原生·容器·k8s·dds·弱网
java_logo16 小时前
Docker 部署 DeepSeek Harness:轻松搭建局域网里的 AI Agent 平台
运维·docker·容器·ai agent·deepseek·轩辕镜像·deepseekharness
weixin_4352470617 小时前
医疗科研“Agent化”:给研究型医院搭AI原生科研平台的3个架构取舍
云原生
安易算力19 小时前
GPU集群调度实践:Slurm/K8s混合部署与GPU共享优化 —— 从批处理到在线推理的统一调度架构
容器·架构·kubernetes
sbjdhjd2 天前
云安全 | Docker 容器逃逸复盘(二):2375 未授权接口如何突破容器管理边界
网络安全·docker·云原生·数据挖掘·开源·云计算·云安全