17-Custom Resource 入门

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

自检问题

  1. 基础 CRD 和 CR 的区别是什么?用数据库类比解释。

  2. 理解 如果只有一个 CRD 没有 Controller,它能做什么?不能做什么?

  3. 应用 你公司想用 K8s 管理 MySQL 集群------创建一个 MySQLCluster CR,设置 replicas: 3,主从自动配置,备份自动执行。哪些部分靠 CRD?哪些部分靠 Controller?

查看答案

  1. CRD = 建表语句(DDL) ,定义字段类型、约束、验证规则。CR = 插入的数据行(DML),是符合 CRD 定义的实例。一个 CRD 可以有多个 CR 实例,就像一张表可以有多行数据。

  2. 有 CRD 没有 Controller:你可以用 kubectl apply/get/describe/delete 操作 CR,数据被存储在 etcd 中,CRD 的 Schema 验证会生效(字段类型、必填等)。但它不会驱动任何实际操作------不会创建 Pod、不会配置网络、不会做任何自动化。就像一个数据库表,你可以插入数据,但没有程序来读取这些数据做事情。

  3. CRD 负责 :定义数据模型------MySQLCluster 的结构(spec: replicas, version, storagesize; status: readyReplicas, primaryNode)。Controller 负责:所有自动化逻辑------创建 StatefulSet、配置主从复制、执行定时备份、更新 status、处理故障切换。CRD = 你要什么,Controller = 怎么做到。两者结合就是 MySQL Operator。

下一步

你已经能扩展 K8s 的 API 了。接下来,学习一种不同于 Helm 的配置管理方式:

28. Kustomize 配置管理

📚 本文来自 K8s Guide ------ 开源免费的 Kubernetes 中文学习指南

  • 🗺️ 初学者轨道 + 面试轨道,从零基础到拿 Offer 一站式覆盖
  • 🧪 每篇文章配套 Kind 实验脚本,本地一键运行
  • 🔗 本文源码:docs/beginner/20-gateway-api.md
  • ⭐ 如果对你有帮助,欢迎 Star! github.com/callmebg/k8s-guide
相关推荐
沉迷学习 日益消瘦2 小时前
14-Pod 安全上下文
安全·kubernetes
腾飞开源4 小时前
01_K8s干货笔记之认识K8s
运维·笔记·云原生·容器·kubernetes·k8s·容器化部署
江湖有缘13 小时前
Docker实战 :使用Docker部署OneTerm堡垒机
运维·docker·容器
张忠琳14 小时前
【NPU】Ascend Docker Runtime v26.0.1 之二 runtime/process/process.go — 超深度逐行分析
云原生·容器·架构·kubernetes·npu·docker-runtime
Kevin Wang72718 小时前
Nvidia-AGX-spark部署手册——课堂质量诊断(jetpack:r36)
python·docker·容器
回眸不遇20 小时前
将 Docker虚拟磁盘文件ext.vhdx迁移出C盘 ,更换到D盘
c语言·docker·容器
雨辰AI20 小时前
K8s人大金仓主从高可用搭建|容器化集群自动同步+故障切换(生产完整版)
云原生·容器·kubernetes
潘正翔21 小时前
k8s基础_kubeadm搭建k8s集群
linux·运维·docker·云原生·容器·kubernetes
Echo flower1 天前
Docker 容器中 Puppeteer 僵尸进程排查与修复
运维·docker·容器·puppeteer