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

文章目录
- Kubernetes CRD(自定义资源,CustomResourceDefinition)详解
-
- 1. 引言
- 2. 基本概念
- 3. CRD 的工作原理
- 4. 如何创建 CRD
- 5. 使用 CRD
- 6. 控制器模式
- 7. 高级特性
-
- 7.1 版本管理
- 7.2 子资源
- 7.3 验证和默认值
- 7.4 附加打印列
- 7.5 最终确定器 (Finalizers)
- 8. 实际应用场景
- 9. 最佳实践和注意事项
- 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 路径,用于处理该自定义资源的请求。其工作流程大致如下:
4. 如何创建 CRD
创建一个 CRD 需要编写 YAML 清单,并通过 kubectl apply 提交。以下是一个简化的 CRD 示例,定义了一个名为 Database 的自定义资源:
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):
apiVersion: example.com/v1alpha1
kind: Database
metadata:
name: mydb
namespace: default
spec:
engine: postgres
version: "13"
storageGB: 100使用 kubectl apply -f database.yaml 创建。
-
查看自定义资源:
kubectl get databases
kubectl get db 使用短名称
kubectl describe database mydb -
直接访问 API: 也可以通过 API Server 的代理访问,例如:
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 生态中进行深度实践的关键一步。


