系列导航
本系列按 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.group | 是 | API Group,自定义的必须是非 *.k8s.io 后缀 |
spec.versions[].name | 是 | 版本号,如 v1、v1alpha1 |
spec.versions[].served | 是 | 是否通过 REST API 对外服务。多版本时,旧的可以 served: false |
spec.versions[].storage | 是 | 只有一个版本可以为 true,决定 Etcd 中实际存储的版本 |
spec.versions[].schema | 是 | OpenAPI v3 Schema,定义 Spec/Status 字段结构和校验规则 |
spec.scope | 是 | Namespaced 或 Cluster |
spec.names.kind | 是 | 首字母大写的驼峰名,YAML 中 kind: 填这个值 |
spec.names.plural | 是 | 小写复数,用于 API 路径:/apis/<group>/<version>/<plural> |
spec.names.shortNames | 否 | 缩写,如 net,kubectl 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?
| 维度 | ConfigMap | CRD |
|---|
| 数据校验 | 无,任意 key-value | OpenAPI 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 中的控制器实现"怎么做" |
参考链接