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 databaseskubectl 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 还支持通过 ValidatingAdmissionWebhookMutatingAdmissionWebhook 实现更复杂的验证和默认值设置。Webhook 可以在资源持久化之前拦截请求,进行自定义逻辑。

7.4 附加打印列

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

7.5 最终确定器 (Finalizers)

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

8. 实际应用场景

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

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

9. 最佳实践和注意事项

  • 设计良好的 API :遵循 Kubernetes API 设计规范,使用 specstatus 分离期望状态和实际状态。
  • 版本规划:从一开始考虑 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 生态中进行深度实践的关键一步。

相关推荐
秋氘渔2 小时前
Docker容器化部署实战指南:Django+Vue
运维·docker·容器
小狗很可爱2 小时前
利用Docker建立个人博客
运维·docker·容器
玉梅小洋2 小时前
修改 Docker 容器主机名
运维·docker·容器
一个向上的运维者2 小时前
从 K8s Device Plugin 到 Volcano 多元算力管理:GPU 显存共享实战与深度解析
云原生·容器·kubernetes
yuanmenghao2 小时前
WSL + Docker GPU 环境排查:NVIDIA-SMI couldn‘t find libnvidia-ml.so 问题分析与解决
linux·运维·服务器·docker·容器
merlin-mm2 小时前
云平台构建 RDMA高性能网络
网络·云原生·容器·kubernetes
上海云盾安全满满2 小时前
云原生环境该怎样解决网络安全问题
安全·web安全·云原生
hanniuniu133 小时前
云原生浪潮起,F5 Web应用防火墙升级
云原生
小二·3 小时前
Go 语言系统编程与云原生开发实战(第37篇)
java·云原生·golang