Kubernetes 内置了 Pod、Service、Deployment 等资源,但在实际平台建设中,团队往往需要描述自己领域的对象,例如数据库实例、流水线任务或租户配额。CustomResourceDefinition(简称 CRD)是 Kubernetes 提供的原生扩展方式,它允许集群管理员向 API 服务器注册新的资源类型,之后用户就能像操作内置资源一样用 kubectl 创建、查看和删除这些自定义对象。

CRD 的核心概念
CRD 本身是一个集群级别的 API 对象,它的作用是告诉 Kubernetes API 服务器:有一种名叫 X 的资源,存放在哪个 API 组和版本下,它的字段结构是什么样子的。当你提交一个 CRD 定义后,apiserver 会动态生成对应的 RESTful 路径,例如 /apis/ippipp.com/v1/redisclusters,无需重启任何组件。
需要注意的是,CRD 只负责“定义资源形状”和“存储校验”,并不包含任何业务逻辑。如果你只装了 CRD 而没有对应的控制器(controller),那么用户创建出来的自定义对象只是被安静地保存在 etcd 中,不会有任何实际动作发生。这也是很多初学者容易混淆的地方:以为定义了 CRD 系统就会自动干活。
一个最小可用的 CRD 示例
下面这段 YAML 声明了一个名为 RedisCluster 的自定义资源,属于 ippipp.com 组,版本 v1,且限定只能挂在命名空间里使用。
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: redisclusters.ippipp.com
spec:
group: ippipp.com
names:
kind: RedisCluster
listKind: RedisClusterList
plural: redisclusters
singular: rediscluster
scope: Namespaced
versions:
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
replicas:
type: integer
minimum: 1
version:
type: string
上述定义中,openAPIV3Schema 部分就是字段校验规则。当用户提交不符合规则的 YAML 时,apiserver 会直接拒绝请求,这比把配置塞进 ConfigMap 再自己写脚本检查要可靠得多。
CRD 与控制器的配合
真正让 CRD 产生价值的是自定义控制器。控制器通过 informer 监听对应资源的变化事件,对比实际状态和期望状态,然后调用 Kubernetes 或其他系统的接口完成调和(reconcile)。这种声明式模型与 Deployment 管理 Pod 的方式完全一致。
例如针对前面的 RedisCluster,控制器可以读取 spec.replicas 并在集群中拉起对应数量的 Redis 实例,同时把真实状态写回 status 字段。下面是一段用 Go 客户端读取自定义对象的简化代码:
package main
import (
"context"
"fmt"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/rest"
)
func main() {
cfg, _ := rest.InClusterConfig()
client, _ := dynamic.NewForConfig(cfg)
// 构造 RedisCluster 的 GVR
gvr := schema.GroupVersionResource{
Group: "ippipp.com",
Version: "v1",
Resource: "redisclusters",
}
list, err := client.Resource(gvr).Namespace("default").List(context.TODO(), metav1.ListOptions{})
if err != nil {
panic(err)
}
for _, item := range list.Items {
fmt.Println(item.GetName())
}
}
通过 dynamic client,我们不必生成强类型代码就能操作任意 CRD,适合写一些轻量工具。但在大型项目中,通常使用 kubebuilder 或 operator-sdk 生成 typed client 和控制器骨架,开发体验更接近内置资源。
版本管理与废弃策略
CRD 支持多版本共存,比如同时提供 v1alpha1 和 v1。你可以标记某个版本 served 为 false 来停止服务,或通过 webhook 做多版本转换。对于需要长期演进的平台来说,这是比 ConfigMap 方案更规范的演进路径。
此外,CRD 还能配置 pruning(默认开启)来自动删除未知字段,以及设置 structural schema 限制,防止用户提交任意嵌套结构。如果未来要废弃某个资源,可以把 served 置为 false 并提前在文档中通知用户迁移,而不是直接删掉导致已有对象无法读取。
使用 CRD 的常见误区
第一个误区是认为 CRD 可以完全替代内置资源。实际上,CRD 的存储和校验都依赖 apiserver,复杂查询和大规模写入性能不如专门设计的数据库,不应把高并发业务数据放进去。
第二个误区是忽略 RBAC。CRD 注册后,默认没有任何用户有权限操作,必须显式绑定 role 才能使用,否则 kubectl 会报 forbidden 错误。下面给出一个简单的角色绑定示例:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: redis-editor
rules:
- apiGroups: ["ippipp.com"]
resources: ["redisclusters"]
verbs: ["get", "list", "create", "update", "delete"]
把该 Role 通过 RoleBinding 绑定到具体用户或 ServiceAccount,才能在对应命名空间内管理 RedisCluster 对象。权限设计和资源定义同等重要,遗漏这一步会让自定义资源形同虚设。
KubernetesCustomResourceDefinitionCRD修改时间:2026-08-11 09:42:28