3. 创建第一个CRD:使用kubectl apply创建自定义资源定义,验证CRD注册成功

在理解了CRD的结构与核心字段之后,我们进入实战环节:通过 kubectl apply 将一个自定义资源定义提交到Kubernetes API Server,完成CRD的注册。这是扩展Kubernetes API的第一步,也是后续编写控制器的基石。

3.1 编写第一个CRD YAML清单

我们以一个管理“数据库实例”的场景为例,定义一个名为 Database 的自定义资源。该CRD属于 example.com API组,版本为 v1,作用域为集群级别(Cluster-scoped),包含两个核心字段:engine(数据库引擎类型)和 version(版本号)。

📄 示例:database-crd.yaml
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: databases.example.com
spec:
  group: example.com
  names:
    kind: Database
    listKind: DatabaseList
    plural: databases
    singular: database
    shortNames:
      - db
  scope: Cluster
  versions:
    - name: v1
      served: true
      storage: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                engine:
                  type: string
                  enum:
                    - mysql
                    - postgres
                    - mongodb
                version:
                  type: string
                  pattern: '^\d+\.\d+\.\d+$'
              required:
                - engine
                - version
字段路径 值 说明
metadata.name databases.example.com CRD名称必须等于 spec.names.plural + "." + spec.group
spec.group example.com API组,用于URL路径:/apis/example.com/v1/...
spec.scope Cluster 集群级别资源,不隶属于任何命名空间
spec.versions[0].schema OpenAPI v3 Schema 定义资源字段结构、类型、枚举约束与正则校验
spec.versions[0].storage true 该版本是持久化存储版本,etcd中以此版本序列化
💡 命名规范: CRD的 metadata.name 必须严格遵循 <plural>.<group> 格式。如果拼写错误,API Server会拒绝注册并返回 422 Unprocessable Entity 错误。

3.2 提交CRD到集群

使用 kubectl apply 将YAML提交到Kubernetes集群。该命令会向API Server发送POST请求,触发CRD的注册流程。

# 提交CRD
kubectl apply -f database-crd.yaml

# 预期输出
customresourcedefinition.apiextensions.k8s.io/databases.example.com created

提交后,API Server会执行以下步骤:

  1. 验证CRD元数据:检查 metadata.name 格式、group 与 names 字段的合法性。
  2. 编译OpenAPI Schema:将 openAPIV3Schema 注册到集群的OpenAPI规范中,用于后续的字段校验。
  3. 创建REST端点:在API Server内部动态生成 /apis/example.com/v1/databases 路由。
  4. 启动CRD控制器:Kube-Controller-Manager中的CRD控制器开始监听该CRD,并为其创建对应的CRD资源实例的存储结构。

3.3 验证CRD注册成功

CRD提交后,可以通过以下三种方式验证注册状态:

方式一:查询CRD列表

kubectl get crd

# 输出示例
NAME                     CREATED AT
databases.example.com    2025-01-15T10:30:00Z

方式二:查看CRD详细信息

kubectl describe crd databases.example.com

# 关键输出片段
Name:         databases.example.com
Group:        example.com
Names:
  Kind:       Database
  List Kind:  DatabaseList
  Plural:     databases
  Singular:   database
  Short Names:
    db
Scope:        Cluster
Version Names:
  v1          SERVED, STORAGE

方式三:直接访问API端点

# 通过kubectl代理访问
kubectl proxy --port=8080 &
curl http://localhost:8080/apis/example.com/v1/databases

# 预期返回(空列表)
{
  "apiVersion": "example.com/v1",
  "kind": "DatabaseList",
  "items": []
}
⚠️ 常见问题: 如果 kubectl get crd 显示 ESTABLISHED 状态为 False,通常是因为OpenAPI Schema中存在语法错误(如字段类型不匹配、缺少 required 字段等)。使用 kubectl describe crd <name> 查看 Conditions 字段中的错误详情。

3.4 CRD注册流程架构图

下图展示了从YAML提交到CRD注册完成的完整流程,以及各组件之间的交互关系:

CRD注册流程架构图 kubectl apply API Server 1. 元数据验证 2. OpenAPI编译 3. REST端点创建 etcd 存储 CRD控制器 4. CRD注册完成 验证命令 kubectl get crd

3.5 创建第一个自定义资源实例

CRD注册成功后,即可创建该类型的自定义资源实例。以下示例创建一个名为 my-production-db 的Database资源:

# database-instance.yaml
apiVersion: example.com/v1
kind: Database
metadata:
  name: my-production-db
spec:
  engine: postgres
  version: "14.5.0"
# 提交资源实例
kubectl apply -f database-instance.yaml

# 预期输出
database.example.com/my-production-db created

# 查询资源实例
kubectl get databases

# 输出示例
NAME                ENGINE    VERSION   AGE
my-production-db    postgres  14.5.0    10s

# 使用短名称查询
kubectl get db

# 输出示例
NAME                ENGINE    VERSION   AGE
my-production-db    postgres  14.5.0    10s
🔍 验证要点:
  • kubectl get databases 返回了自定义资源实例,说明CRD已成功注册并可用。
  • 短名称 db 生效,简化了日常操作。
  • 如果尝试创建 engine: oracle(不在枚举值中),API Server会返回校验错误,拒绝创建。

3.6 注册状态检查清单

检查项 命令 成功标志
CRD是否存在 kubectl get crd databases.example.com 返回CRD对象,ESTABLISHED 状态为 True
API端点是否可用 kubectl proxy + curl /apis/example.com/v1/databases 返回 200 OK,响应中包含 DatabaseList
资源实例能否创建 kubectl apply -f instance.yaml 返回 created,无校验错误
字段校验是否生效 尝试创建非法字段值(如 engine: oracle) API Server返回 422 或 400 错误
短名称是否注册 kubectl get db 返回与 kubectl get databases 相同的结果
💡 生产建议: 在CI/CD流水线中,建议将CRD的注册与资源实例的创建分离。先提交CRD并等待 ESTABLISHED 状态变为 True(通常需要几秒钟),再提交资源实例。可以使用 kubectl wait --for=condition=Established crd/databases.example.com --timeout=60s 实现等待逻辑。