Custom Resource 入门
概念引入
到目前为止你已经用过十几种 K8s 内置资源了------Pod、Deployment、Service、Ingress、NetworkPolicy......但你知道 K8s 还能自定义资源类型吗?
K8s 内置了 Deployment、Service、ConfigMap 等资源。但每个公司的业务需求千差万别------K8s 不可能内置所有资源类型。
Custom Resource Definition (CRD) 让你自己定义新的资源类型,然后像操作 Deployment 一样用 kubectl 管理它:
K8s 内置资源 你自定义的资源
───────────── ──────────────────
Deployment MySQLCluster
Service TLSStore
ConfigMap AlertRule
Pod DataPipeline
#mermaid-svg-9GGzx9tEjrwJz7iK{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-9GGzx9tEjrwJz7iK .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-9GGzx9tEjrwJz7iK .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-9GGzx9tEjrwJz7iK .error-icon{fill:#552222;}#mermaid-svg-9GGzx9tEjrwJz7iK .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-9GGzx9tEjrwJz7iK .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-9GGzx9tEjrwJz7iK .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-9GGzx9tEjrwJz7iK .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-9GGzx9tEjrwJz7iK .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-9GGzx9tEjrwJz7iK .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-9GGzx9tEjrwJz7iK .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-9GGzx9tEjrwJz7iK .marker{fill:#333333;stroke:#333333;}#mermaid-svg-9GGzx9tEjrwJz7iK .marker.cross{stroke:#333333;}#mermaid-svg-9GGzx9tEjrwJz7iK svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-9GGzx9tEjrwJz7iK p{margin:0;}#mermaid-svg-9GGzx9tEjrwJz7iK .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-9GGzx9tEjrwJz7iK .cluster-label text{fill:#333;}#mermaid-svg-9GGzx9tEjrwJz7iK .cluster-label span{color:#333;}#mermaid-svg-9GGzx9tEjrwJz7iK .cluster-label span p{background-color:transparent;}#mermaid-svg-9GGzx9tEjrwJz7iK .label text,#mermaid-svg-9GGzx9tEjrwJz7iK span{fill:#333;color:#333;}#mermaid-svg-9GGzx9tEjrwJz7iK .node rect,#mermaid-svg-9GGzx9tEjrwJz7iK .node circle,#mermaid-svg-9GGzx9tEjrwJz7iK .node ellipse,#mermaid-svg-9GGzx9tEjrwJz7iK .node polygon,#mermaid-svg-9GGzx9tEjrwJz7iK .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-9GGzx9tEjrwJz7iK .rough-node .label text,#mermaid-svg-9GGzx9tEjrwJz7iK .node .label text,#mermaid-svg-9GGzx9tEjrwJz7iK .image-shape .label,#mermaid-svg-9GGzx9tEjrwJz7iK .icon-shape .label{text-anchor:middle;}#mermaid-svg-9GGzx9tEjrwJz7iK .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-9GGzx9tEjrwJz7iK .rough-node .label,#mermaid-svg-9GGzx9tEjrwJz7iK .node .label,#mermaid-svg-9GGzx9tEjrwJz7iK .image-shape .label,#mermaid-svg-9GGzx9tEjrwJz7iK .icon-shape .label{text-align:center;}#mermaid-svg-9GGzx9tEjrwJz7iK .node.clickable{cursor:pointer;}#mermaid-svg-9GGzx9tEjrwJz7iK .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-9GGzx9tEjrwJz7iK .arrowheadPath{fill:#333333;}#mermaid-svg-9GGzx9tEjrwJz7iK .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-9GGzx9tEjrwJz7iK .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-9GGzx9tEjrwJz7iK .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-9GGzx9tEjrwJz7iK .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-9GGzx9tEjrwJz7iK .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-9GGzx9tEjrwJz7iK .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-9GGzx9tEjrwJz7iK .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-9GGzx9tEjrwJz7iK .cluster text{fill:#333;}#mermaid-svg-9GGzx9tEjrwJz7iK .cluster span{color:#333;}#mermaid-svg-9GGzx9tEjrwJz7iK div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-9GGzx9tEjrwJz7iK .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-9GGzx9tEjrwJz7iK rect.text{fill:none;stroke-width:0;}#mermaid-svg-9GGzx9tEjrwJz7iK .icon-shape,#mermaid-svg-9GGzx9tEjrwJz7iK .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-9GGzx9tEjrwJz7iK .icon-shape p,#mermaid-svg-9GGzx9tEjrwJz7iK .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-9GGzx9tEjrwJz7iK .icon-shape .label rect,#mermaid-svg-9GGzx9tEjrwJz7iK .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-9GGzx9tEjrwJz7iK .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-9GGzx9tEjrwJz7iK .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-9GGzx9tEjrwJz7iK :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 你定义的
K8s 内置
kubectl apply -f
kubectl apply -f
Deployment
Service
ConfigMap
MySQLCluster
(你的 CRD)
AlertRule
(你的 CRD)
etcd
(和其他资源一样存储)
学完本篇你将能够:
- 编写 CRD YAML,定义一个全新的 K8s 资源类型(含字段和验证规则)
- 创建、查询、删除 Custom Resource 实例,像操作 Deployment 一样用 kubectl 管理
- 理解 CRD 与 Operator 的关系,为后续学习 Operator 打基础
原理讲解
CRD + CR = 自定义资源
两个概念需要区分:
| 概念 | 全称 | 作用 | 类比 |
|---|---|---|---|
| CRD | Custom Resource Definition | 定义类型(模板) | 数据库建表 CREATE TABLE |
| CR | Custom Resource | 类型的实例(数据) | 插入数据 INSERT INTO |
#mermaid-svg-wYI28MO2IcOABu2A{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-wYI28MO2IcOABu2A .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-wYI28MO2IcOABu2A .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-wYI28MO2IcOABu2A .error-icon{fill:#552222;}#mermaid-svg-wYI28MO2IcOABu2A .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-wYI28MO2IcOABu2A .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-wYI28MO2IcOABu2A .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-wYI28MO2IcOABu2A .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-wYI28MO2IcOABu2A .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-wYI28MO2IcOABu2A .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-wYI28MO2IcOABu2A .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-wYI28MO2IcOABu2A .marker{fill:#333333;stroke:#333333;}#mermaid-svg-wYI28MO2IcOABu2A .marker.cross{stroke:#333333;}#mermaid-svg-wYI28MO2IcOABu2A svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-wYI28MO2IcOABu2A p{margin:0;}#mermaid-svg-wYI28MO2IcOABu2A .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-wYI28MO2IcOABu2A .cluster-label text{fill:#333;}#mermaid-svg-wYI28MO2IcOABu2A .cluster-label span{color:#333;}#mermaid-svg-wYI28MO2IcOABu2A .cluster-label span p{background-color:transparent;}#mermaid-svg-wYI28MO2IcOABu2A .label text,#mermaid-svg-wYI28MO2IcOABu2A span{fill:#333;color:#333;}#mermaid-svg-wYI28MO2IcOABu2A .node rect,#mermaid-svg-wYI28MO2IcOABu2A .node circle,#mermaid-svg-wYI28MO2IcOABu2A .node ellipse,#mermaid-svg-wYI28MO2IcOABu2A .node polygon,#mermaid-svg-wYI28MO2IcOABu2A .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-wYI28MO2IcOABu2A .rough-node .label text,#mermaid-svg-wYI28MO2IcOABu2A .node .label text,#mermaid-svg-wYI28MO2IcOABu2A .image-shape .label,#mermaid-svg-wYI28MO2IcOABu2A .icon-shape .label{text-anchor:middle;}#mermaid-svg-wYI28MO2IcOABu2A .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-wYI28MO2IcOABu2A .rough-node .label,#mermaid-svg-wYI28MO2IcOABu2A .node .label,#mermaid-svg-wYI28MO2IcOABu2A .image-shape .label,#mermaid-svg-wYI28MO2IcOABu2A .icon-shape .label{text-align:center;}#mermaid-svg-wYI28MO2IcOABu2A .node.clickable{cursor:pointer;}#mermaid-svg-wYI28MO2IcOABu2A .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-wYI28MO2IcOABu2A .arrowheadPath{fill:#333333;}#mermaid-svg-wYI28MO2IcOABu2A .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-wYI28MO2IcOABu2A .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-wYI28MO2IcOABu2A .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-wYI28MO2IcOABu2A .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-wYI28MO2IcOABu2A .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-wYI28MO2IcOABu2A .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-wYI28MO2IcOABu2A .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-wYI28MO2IcOABu2A .cluster text{fill:#333;}#mermaid-svg-wYI28MO2IcOABu2A .cluster span{color:#333;}#mermaid-svg-wYI28MO2IcOABu2A div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-wYI28MO2IcOABu2A .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-wYI28MO2IcOABu2A rect.text{fill:none;stroke-width:0;}#mermaid-svg-wYI28MO2IcOABu2A .icon-shape,#mermaid-svg-wYI28MO2IcOABu2A .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-wYI28MO2IcOABu2A .icon-shape p,#mermaid-svg-wYI28MO2IcOABu2A .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-wYI28MO2IcOABu2A .icon-shape .label rect,#mermaid-svg-wYI28MO2IcOABu2A .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-wYI28MO2IcOABu2A .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-wYI28MO2IcOABu2A .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-wYI28MO2IcOABu2A :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 创建实例(CR)
定义类型(CRD)
定义结构
定义结构
kind: CustomResourceDefinition
定义字段、验证规则
kind: MySQLCluster
name: prod-db
replicas: 3
kind: MySQLCluster
name: staging-db
replicas: 1
创建一个简单的 CRD
yaml
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: websiteinfos.example.com # <plural>.<group>
spec:
group: example.com # API 组
versions:
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
url:
type: string
maintainer:
type: string
replicas:
type: integer
minimum: 1
maximum: 10
required: ["url"]
scope: Namespaced # 或 Cluster
names:
plural: websiteinfos # kubectl get websiteinfos
singular: websiteinfo # kubectl get websiteinfo/xxx
kind: WebsiteInfo # YAML 中 kind 的值
shortNames: # kubectl get wi
- wi
CRD 关键配置
| 字段 | 含义 | 示例 |
|---|---|---|
group |
API 组(自定义的必须用非 k8s.io 域名) | example.com |
scope |
Namespaced(Namespace 隔离)或 Cluster(集群级) |
Namespaced |
names.plural |
复数名(用于 URL 路径) | websiteinfos |
names.kind |
资源类型名(YAML 中的 kind) | WebsiteInfo |
versions |
支持的 API 版本列表 | v1, v1beta1 |
schema |
用 OpenAPI v3 Schema 验证 CR 字段 | JSON Schema |
操作 CR
CRD 创建后,就可以像操作内置资源一样操作自定义资源:
yaml
apiVersion: example.com/v1
kind: WebsiteInfo
metadata:
name: my-blog
spec:
url: "https://myblog.com"
maintainer: "bg"
replicas: 3
bash
# 增删改查------和 Deployment 完全一样的命令
kubectl apply -f websiteinfo.yaml
kubectl get websiteinfos # 或简写 kubectl get wi
kubectl get wi my-blog -o yaml
kubectl describe wi my-blog
kubectl delete wi my-blog
CRD 有什么用?
光有 CRD 只是把数据存到 etcd。要让 CR 真正驱动自动化操作------你需要 Controller(控制器):
CRD 只是数据模型 → 定义了"数据库表结构"
CRD + Controller = Operator → 你的自定义自动化平台
#mermaid-svg-iVpBmwmkEpe8dZbK{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-iVpBmwmkEpe8dZbK .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-iVpBmwmkEpe8dZbK .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-iVpBmwmkEpe8dZbK .error-icon{fill:#552222;}#mermaid-svg-iVpBmwmkEpe8dZbK .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-iVpBmwmkEpe8dZbK .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-iVpBmwmkEpe8dZbK .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-iVpBmwmkEpe8dZbK .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-iVpBmwmkEpe8dZbK .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-iVpBmwmkEpe8dZbK .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-iVpBmwmkEpe8dZbK .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-iVpBmwmkEpe8dZbK .marker{fill:#333333;stroke:#333333;}#mermaid-svg-iVpBmwmkEpe8dZbK .marker.cross{stroke:#333333;}#mermaid-svg-iVpBmwmkEpe8dZbK svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-iVpBmwmkEpe8dZbK p{margin:0;}#mermaid-svg-iVpBmwmkEpe8dZbK .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-iVpBmwmkEpe8dZbK .cluster-label text{fill:#333;}#mermaid-svg-iVpBmwmkEpe8dZbK .cluster-label span{color:#333;}#mermaid-svg-iVpBmwmkEpe8dZbK .cluster-label span p{background-color:transparent;}#mermaid-svg-iVpBmwmkEpe8dZbK .label text,#mermaid-svg-iVpBmwmkEpe8dZbK span{fill:#333;color:#333;}#mermaid-svg-iVpBmwmkEpe8dZbK .node rect,#mermaid-svg-iVpBmwmkEpe8dZbK .node circle,#mermaid-svg-iVpBmwmkEpe8dZbK .node ellipse,#mermaid-svg-iVpBmwmkEpe8dZbK .node polygon,#mermaid-svg-iVpBmwmkEpe8dZbK .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-iVpBmwmkEpe8dZbK .rough-node .label text,#mermaid-svg-iVpBmwmkEpe8dZbK .node .label text,#mermaid-svg-iVpBmwmkEpe8dZbK .image-shape .label,#mermaid-svg-iVpBmwmkEpe8dZbK .icon-shape .label{text-anchor:middle;}#mermaid-svg-iVpBmwmkEpe8dZbK .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-iVpBmwmkEpe8dZbK .rough-node .label,#mermaid-svg-iVpBmwmkEpe8dZbK .node .label,#mermaid-svg-iVpBmwmkEpe8dZbK .image-shape .label,#mermaid-svg-iVpBmwmkEpe8dZbK .icon-shape .label{text-align:center;}#mermaid-svg-iVpBmwmkEpe8dZbK .node.clickable{cursor:pointer;}#mermaid-svg-iVpBmwmkEpe8dZbK .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-iVpBmwmkEpe8dZbK .arrowheadPath{fill:#333333;}#mermaid-svg-iVpBmwmkEpe8dZbK .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-iVpBmwmkEpe8dZbK .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-iVpBmwmkEpe8dZbK .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-iVpBmwmkEpe8dZbK .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-iVpBmwmkEpe8dZbK .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-iVpBmwmkEpe8dZbK .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-iVpBmwmkEpe8dZbK .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-iVpBmwmkEpe8dZbK .cluster text{fill:#333;}#mermaid-svg-iVpBmwmkEpe8dZbK .cluster span{color:#333;}#mermaid-svg-iVpBmwmkEpe8dZbK div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-iVpBmwmkEpe8dZbK .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-iVpBmwmkEpe8dZbK rect.text{fill:none;stroke-width:0;}#mermaid-svg-iVpBmwmkEpe8dZbK .icon-shape,#mermaid-svg-iVpBmwmkEpe8dZbK .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-iVpBmwmkEpe8dZbK .icon-shape p,#mermaid-svg-iVpBmwmkEpe8dZbK .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-iVpBmwmkEpe8dZbK .icon-shape .label rect,#mermaid-svg-iVpBmwmkEpe8dZbK .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-iVpBmwmkEpe8dZbK .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-iVpBmwmkEpe8dZbK .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-iVpBmwmkEpe8dZbK :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} kubectl apply CR
CR 变更事件
调和(Reconcile)
创建 Pod/Service/等
你
etcd
Controller
(你的自定义逻辑)
K8s API
Operator 框架(如 kubebuilder, operator-sdk)帮你生成 CRD 和 Controller 脚手架,但本篇只讲 CRD------理解数据模型是后续 Operator 开发的基础。
动手实验
配套实验位于
docs/labs/beginner/custom-resource/
步骤 1:部署实验环境
bash
cd docs/labs/beginner/custom-resource
bash setup.sh
步骤 2:创建 CRD
bash
kubectl apply -f manifests/websiteinfo-crd.yaml
kubectl get crd
# 输出中包含 websiteinfos.example.com
# 查看 API 资源列表(你的 CRD 已在其中)
kubectl api-resources | grep example
步骤 3:创建自定义资源实例
bash
kubectl apply -f manifests/my-website.yaml
kubectl get websiteinfos
kubectl get wi # 简写也可以
步骤 4:体验 CRD 的验证能力
bash
# 尝试创建一个无效的 CR(replicas: 100 超过了 maximum: 10)
kubectl apply -f manifests/invalid-website.yaml
# 预期:错误信息指出 replicas 超过了最大值
步骤 5:查看和删除
bash
kubectl describe wi my-blog
kubectl get wi my-blog -o yaml
kubectl delete wi my-blog
步骤 6:清理
bash
bash teardown.sh
自检问题
-
基础 CRD 和 CR 的区别是什么?用数据库类比解释。
-
理解 如果只有一个 CRD 没有 Controller,它能做什么?不能做什么?
-
应用 你公司想用 K8s 管理 MySQL 集群------创建一个
MySQLClusterCR,设置replicas: 3,主从自动配置,备份自动执行。哪些部分靠 CRD?哪些部分靠 Controller?
查看答案
-
CRD = 建表语句(DDL) ,定义字段类型、约束、验证规则。CR = 插入的数据行(DML),是符合 CRD 定义的实例。一个 CRD 可以有多个 CR 实例,就像一张表可以有多行数据。
-
有 CRD 没有 Controller:你可以用
kubectl apply/get/describe/delete操作 CR,数据被存储在 etcd 中,CRD 的 Schema 验证会生效(字段类型、必填等)。但它不会驱动任何实际操作------不会创建 Pod、不会配置网络、不会做任何自动化。就像一个数据库表,你可以插入数据,但没有程序来读取这些数据做事情。 -
CRD 负责 :定义数据模型------MySQLCluster 的结构(spec: replicas, version, storagesize; status: readyReplicas, primaryNode)。Controller 负责:所有自动化逻辑------创建 StatefulSet、配置主从复制、执行定时备份、更新 status、处理故障切换。CRD = 你要什么,Controller = 怎么做到。两者结合就是 MySQL Operator。
下一步
你已经能扩展 K8s 的 API 了。接下来,学习一种不同于 Helm 的配置管理方式:
📚 本文来自 K8s Guide ------ 开源免费的 Kubernetes 中文学习指南
- 🗺️ 初学者轨道 + 面试轨道,从零基础到拿 Offer 一站式覆盖
- 🧪 每篇文章配套 Kind 实验脚本,本地一键运行
- 🔗 本文源码:docs/beginner/20-gateway-api.md
- ⭐ 如果对你有帮助,欢迎 Star! github.com/callmebg/k8s-guide