目录
Please enable Javascript to view the contents

K8s扩展-CRD概念与使用

 ·  ☕ 4 分钟

系列导航

本系列按 K8S 扩展机制递进展开:

顺序文章定位
本篇 - CRD 概念与使用数据模型扩展——CRD 的定义、校验、版本管理
Operator逻辑扩展——自定义控制器 + Informer + RBAC + Operator 模式

1. CRD 是什么

CRD(CustomResourceDefinition)是 Kubernetes 内置的一种资源类型,用于向 K8S API 注册自定义资源类型

注册后,就像操作内置 Pod/Deployment 一样,可以对自定义资源执行 kubectl get/create/delete

1
2
3
4
5
6
7
8
9
K8S 扩展机制层级:

CRD(数据模型层)
  └── 定义 "什么是我的资源",确定 Spec/Status 结构

自定义控制器(业务逻辑层)
  └── 监听 CR 变化,执行调谐逻辑

Operator = CRD + 自定义控制器 + 领域知识

2. CRD 定义

2.1 最小示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: networks.samplecrd.k8s.io
spec:
  group: samplecrd.k8s.io
  versions:
    - name: v1
      served: true
      storage: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                cidr:
                  type: string
                gateway:
                  type: string
  scope: Namespaced
  names:
    plural: networks
    singular: network
    kind: Network
    shortNames:
      - net

2.2 关键字段说明

字段必填说明
metadata.name格式必须为 <plural>.<group>,如 networks.samplecrd.k8s.io
spec.groupAPI Group,自定义的必须是非 *.k8s.io 后缀
spec.versions[].name版本号,如 v1v1alpha1
spec.versions[].served是否通过 REST API 对外服务。多版本时,旧的可以 served: false
spec.versions[].storage只有一个版本可以为 true,决定 Etcd 中实际存储的版本
spec.versions[].schemaOpenAPI v3 Schema,定义 Spec/Status 字段结构和校验规则
spec.scopeNamespacedCluster
spec.names.kind首字母大写的驼峰名,YAML 中 kind: 填这个值
spec.names.plural小写复数,用于 API 路径:/apis/<group>/<version>/<plural>
spec.names.shortNames缩写,如 netkubectl get net

2.3 scope:Namespaced vs Cluster

scope含义API 路径删除时
Namespaced资源属于某个 Namespace/apis/<group>/<version>/namespaces/<ns>/<plural>删 Namespace 时一并删除
Cluster集群级别资源,不属于任何 Namespace/apis/<group>/<version>/<plural>不随 Namespace 删除

2.4 OpenAPI Schema 校验

CRD 通过 OpenAPI v3 Schema 定义字段验证规则:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
schema:
  openAPIV3Schema:
    type: object
    required: ["spec"]
    properties:
      spec:
        type: object
        required: ["cidr"]
        properties:
          cidr:
            type: string
            pattern: '^([0-9]{1,3}\.){3}[0-9]{1,3}/[0-9]{1,2}$'
          gateway:
            type: string
          replicas:
            type: integer
            minimum: 1
            maximum: 10
      status:
        type: object
        properties:
          availableReplicas:
            type: integer
          conditions:
            type: array
            items:
              type: object
              properties:
                type:
                  type: string
                status:
                  type: string
                lastTransitionTime:
                  type: string
                  format: date-time

提交不合规的 CR 时,API Server 直接拒绝并返回明确的错误信息:

1
2
The Network "invalid-net" is invalid: spec.replicas: Invalid value: 20: 
spec.replicas in body should be less than or equal to 10

2.5 多版本管理

CRD 支持同时暴露多个版本,运行时通过 Webhook 做版本转换:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
spec:
  versions:
    - name: v1alpha1        # 早期实验版本
      served: true           # 仍可访问
      storage: false         # 不存储到 Etcd
    - name: v1               # 稳定版本
      served: true
      storage: true          # Etcd 只存这个版本
  conversion:
    strategy: Webhook        # 用 Webhook 做版本转换
    webhook:
      conversionReviewVersions: ["v1", "v1alpha1"]
      clientConfig:
        service:
          namespace: default
          name: crd-conversion-webhook
          path: /convert

多版本处理规则:

场景行为
所有读写API Server 用 storage: true 的版本存取 Etcd
旧版本请求API Server 调用 Conversion Webhook,将存储版本转换为请求版本返回
新版本写入API Server 调用 Conversion Webhook,将请求版本转换为存储版本写入

3. 创建和使用 CR

部署 CRD 后即可创建对应的 CR(Custom Resource):

1
kubectl apply -f network-crd.yaml
1
2
3
4
5
6
7
8
# 创建 Network CR
apiVersion: samplecrd.k8s.io/v1
kind: Network
metadata:
  name: my-network
spec:
  cidr: "10.244.0.0/16"
  gateway: "10.244.0.1"

操作与内置资源一致:

1
2
3
kubectl get networks
kubectl describe network my-network
kubectl delete network my-network

4. CRD 的底层实现

CRD 本质上是向 apiextensions.k8s.io API Group 注册一个 CRD 对象。API Server 中的 apiextensions-apiserver 组件收到 CRD 后:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
kubectl apply -f network-crd.yaml
API Server (apiextensions-apiserver)
1. 注册 API 路由:
   /apis/samplecrd.k8s.io/v1/networks
2. 创建对应的 RESTful API Handler
   GET    → List / Get
   POST   → Create
   PUT    → Update / Replace
   PATCH  → Patch
   DELETE → Delete
3. 实际存储:所有 CR 对象以 JSON 格式存入 Etcd
   路径:/registry/<group>/<plural>/<namespace>/<name>

这意味着 CRD 不需要你编写任何 API Server 代码——Kubernetes 自动为 CRD 生成 CRUD HTTP 端点。

5. CRD vs ConfigMap

常见误区:用 ConfigMap 存配置,写一个控制器来解析。为什么不直接用 ConfigMap?

维度ConfigMapCRD
数据校验无,任意 key-valueOpenAPI v3 Schema 校验
版本管理多版本 served/storage 控制
API 语义通用 KV,无类型kubectl get <resource>,类型明确
RBAC 控制只能到 ConfigMap 级别可以精确到具体 CRD 类型
Status 子资源不支持支持 /status 子资源,控制器只写 Status
客户端库支持client-gen / informer-gen 自动生成类型安全客户端
生态集成需要自己解析Operator Framework、KubeBuilder 直接支持

建议:只要你的配置有固定结构、需要校验、需要控制器监听,用 CRD 而不是 ConfigMap。

6. 删除 CRD 的影响

1
kubectl delete crd networks.samplecrd.k8s.io
删除对象行为
CRD 对象被删除
所有对应的 CR 对象一并删除(级联删除)
API 路由被移除,kubectl get networks 不再可用
Etcd 中数据被清理

CRD 删除是级联的,生产环境需确认 CR 数据已备份或不再需要。

7. 总结

要点说明
CRD 定位向 K8S API 注册自定义资源,自动生成 CRUD 端点
Schema 校验OpenAPI v3,在 API Server 层拦截非法请求
多版本storage: true 决定存储版本,Conversion Webhook 做版本转换
与 ConfigMap 区别CRD 有 Schema、版本、RBAC 粒度、Status 子资源
与 Operator 关系CRD 定义"是什么",Operator 中的控制器实现"怎么做"

参考链接

分享

Hex
作者
Hex
CloudNative Developer