文章目录
- Kubernetes Operator CRD/CR 深度解析报告
-
- 目录
- 一、核心概念快速理解
-
- 1.0 历史与哲学背景
-
- Kubernetes 的历史演进
- Operator 的哲学本质
- 1.1 生活场景类比
- 1.2 概念定义对照表
- 1.3 Spec vs Status:两个状态字段
- 1.4 三者关系的精确定义
- 二、API 资源概览
-
- 2.1 `kubectl api-resources` 输出解读
- 2.2 内置资源 vs 自定义资源
- 2.3 实际环境中的 OceanBase 资源
- 三、CRD/CR/Operator 代码级解析
-
- 3.1 CRD 定义(YAML → Go 结构体)
-
- 实际 CRD 定义
- CRD 对应的 Go 结构体(生成的代码)
- 3.2 CR(Custom Resource)的内存结构
- 四、调谐循环(Reconcile)代码实现
-
- 4.1 完整的 Reconcile Loop 流程图
- 4.2 Reconcile 函数代码详解
- 五、状态机(State Machine)与事件
-
- 5.1 Operator 状态机
- 5.2 状态机流程图
- 5.3 Watch 事件驱动机制
- 六、OceanBase 实战案例
-
- 6.1 实际环境信息(脱敏)
- 6.2 验证步骤与实际输出
- 6.3 集群架构拓扑
- 6.4 集群配置参数说明
- 七、通用学习指南
-
- 7.1 学习任何 Operator 的六步法
- 7.2 主流数据库 Operator 对比
- 7.3 Operator 开发框架对比
- 附录:快速参考
-
- A. kubectl api-resources 命令详解
- B. 常用调试命令
- C. 术语对照表
Kubernetes Operator CRD/CR 深度解析报告
报告日期:2026-03-05 环境目标:生产环境 Kubernetes 集群 主题:从代码级别理解 Operator、CRD、CR 的底层原理
目录
一、核心概念快速理解
1.0 历史与哲学背景
Kubernetes 的历史演进
Kubernetes(希腊语"舵手")的诞生并非偶然,而是云计算发展历程中的重要里程碑:
┌─────────────────────────────────────────────────────────────────────┐
│ Kubernetes 哲学观 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 【核心哲学】 │
│ │
│ 1. 声明式优于命令式 (Declarative over Imperative) │
│ "告诉系统你想要什么,而不是如何做" │
│ │
│ 2. 控制理论 (Control Theory) │
│ 从工业控制理论借鉴,引入 Reconciliation Loop(调谐循环) │
│ │
│ 3. 不可变基础设施 (Immutable Infrastructure) │
│ 用声明式配置管理,而非持续修改运行时状态 │
│ │
│ 4. 自愈性 (Self-healing) │
│ "期望 – 实际 – 调整"的持续循环 │
│ │
└─────────────────────────────────────────────────────────────────────┘
关键历史节点:
| 2014 | Google 开源 Kubernetes | 将 Google Borg 十年经验公开 |
| 2015 | v1.0 发布 | 生产就绪 |
| 2016 | CRD 成为稳定特性 | 允许用户扩展 API |
| 2018 | Operator 模式普及 | CoreOS 提出 Operator 模式 |
| 2020+ | Operator 生态爆发 | 数据库、中间件、AI 等全面 Operator 化 |
从 Docker 到 Kubernetes 的哲学转变:
【命令式思维 – Docker】
→ 手动执行命令
→ 持续修改状态
→ 依赖人工决策
【声明式思维 – Kubernetes】
→ 定义期望状态
→ 系统自动调谐
→ 状态驱动的自愈
Operator 的哲学本质
Operator 模式的提出,源于对 Kubernetes 控制器模式的深刻理解:
设计哲学:
- 将运维专家的经验固化到代码中
- 让"人"的经验成为"系统"的能力
- 声明式描述期望状态
- 系统持续调谐以达成目标
- Kubernetes 不预设所有应用场景
- 通过 CRD 和 Operator 扩展能力边界
期望状态 ──▶ 控制器 ──▶ 实际状态
▲ │
└──────── 调谐循环 ───────┘
1.1 生活场景类比
想象你在管理一个餐厅:
┌─────────────────────────────────────────────────────────────────────┐
│ 餐厅管理系统 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 内置功能: │
│ • 桌子预订 │
│ • 菜单管理 │
│ • 收银台 │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 你想添加的特殊功能 │ │
│ │ │ │
│ │ ① 定义"包间"这种特殊桌型 ──▶ CRD │ │
│ │ ② 预订一间具体的包间 ──▶ CR │ │
│ │ ③ 安排服务员按照包间规则服务 ──▶ Operator │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
对应关系:
| 定义"包间"是特殊桌型 | CRD | 定义一种新的资源类型 |
| 预订"202 号包间" | CR | 具体的资源实例 |
| 安排专门的服务员处理包间 | Operator | 管理这种资源的专门逻辑 |
1.2 概念定义对照表
| CRD | Custom Resource Definition | 扩展 Kubernetes API 的"类型模板",告诉系统"有什么新东西" | class User { name, age } |
| CR | Custom Resource | CRD 的具体实例,即"某个东西" | user1 = new User("张三", 25) |
| Operator | 操作器/运算符 | 结合 CRD + 控制器逻辑,实现应用自动化运维的智能代理 | while(true) { sync(user1) } |
| Controller | 控制器 | Operator 的核心组件,负责比较期望与实际状态 | 循环中的比较逻辑 |
| Reconcile | 调谐 | 不断比较并调整状态的过程 | 期望 – 实际 = 差异 → 执行调整 |
1.3 Spec vs Status:两个状态字段
| spec | 期望状态(用户想要什么) | 用户通过 YAML 文件定义 | replicas: 3, version: "4.3.5" |
| status | 实际状态(系统实际是什么) | Operator 自动填写 | availableReplicas: 3, phase: "Running" |
关键理解:
- spec 是输入(你告诉系统要做什么)
- status 是输出(系统告诉你现在怎么样)
- Operator 的职责就是:不断让 status 向 spec 收敛
1.4 三者关系的精确定义
┌─────────────────────────────────────────────────────────────────────┐
│ Kubernetes API Server │
│ (系统的大门,统一 API 入口) │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 内置资源(Kubernetes 自带的) │ │
│ │ • Pod • Deployment • Service │ │
│ │ • ConfigMap • Secret • Ingress │ │
│ │ (这些是系统自带的,不需要定义) │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ════════════════════════════════════════════════════════ │
│ ║ 自定义资源层(用户扩展的) │ ║
│ ║ │ ║
│ ║ CRD(类定义) CR(实例) │ ║
│ ║ ┌─────────────┐ ┌──────────────────┐ │ ║
│ ║ │ 【定义】 │ │ 【实例】 │ │ ║
│ ║ │ "数据库集群" │ │ │ "生产数据库集群" │ │ ║
│ ║ │ • 副本数 │ │ │ │ • name: prod-db │ │ ║
│ ║ │ • 版本 │ │ │ │ • replicas: 3 │ │ ║
│ ║ │ • 存储配置 │ │ │ │ • version: 4.2 │ │ ║
│ ║ └─────────────┘ └──────────────────┘ │ ║
│ ║ │ │ ║
│ ║ ▼ │ ║
│ ║ ┌─────────────────────────────────────────────┐ │ ║
│ ║ │ Operator (3) │ │ ║
│ ║ │ 【智能管家】 │ │ ║
│ ║ │ │ │ ║
│ ║ │ 持续监听 CR 的变化 │ │ ║
│ ║ │ 读取期望状态 │ │ ║
│ ║ │ 查询实际状态 │ │ ║
│ ║ │ 计算差异 │ │ ║
│ ║ │ 执行调谐动作 │ │ ║
│ ║ │ 更新 CR 的状态 │ │ ║
│ ║ └─────────────────────────────────────────────┘ │ ║
│ ╚═════════════════════════════════════════════════════ │
│ │
└─────────────────────────────────────────────────────────────────────┘
二、API 资源概览
2.1 kubectl api-resources 输出解读
$ kubectl api-resources
| NAME | 资源类型全名 | pods, services, oceanbaseclusters |
| SHORTNAMES | 缩写别名 | po, svc, obc |
| APIGROUP | API 组名 | v1, apps/v1, oceanbase.woqutech.com/v1 |
| NAMESPACED | 是否命名空间级别 | true = 需要指定 namespace |
| KIND | 资源类型 | Pod, Service, CustomResource |
| VERBS | 支持的 HTTP 动词 | create, get, list, watch, patch, update, delete |
2.2 内置资源 vs 自定义资源
┌─────────────────────────────────────────────────────────────────────┐
│ Kubernetes API 资源分层 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Core API(核心组,v1) │ │
│ │ ┌──────────────────────────────────────────────┐ │ │
│ │ │ • Pod • Node │ │ │
│ │ │ • Service • Namespace │ │ │
│ │ │ • ConfigMap • Event │ │ │
│ │ └──────────────────────────────────────────────┘ │ │
│ │ APIGROUP: v1, NAMESPACE: true/false │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Apps API(应用组,apps/v1) │ │
│ │ ┌──────────────────────────────────────────────┐ │ │
│ │ │ • Deployment • StatefulSet │ │ │
│ │ │ • DaemonSet • ReplicaSet │ │ │
│ │ └──────────────────────────────────────────────┘ │ │
│ │ APIGROUP: apps/v1, NAMESPACE: true │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ══════════════════════════════════════════════════════════════ │
│ ║ Custom Resource(自定义资源) │ ║
│ ║ │ ║
│ ║ OceanBase Cluster: │ ║
│ ║ apiGroup: oceanbase.woqutech.com/v1 │ ║
│ ║ kind: OceanbaseCluster │ ║
│ ║ NAMESPACE: true │ ║
│ ║ │ ║
│ ║ MySQL Cluster: │ ║
│ ║ apiGroup: mysql.woqutech.com/v1 │ ║
│ ║ kind: MysqlCluster │ ║
│ ║ NAMESPACE: true │ ║
│ ║ │ ║
│ ╚═══════════════════════════════════════════════════ │
│ │ 这些都是通过 CRD 扩展的资源 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
2.3 实际环境中的 OceanBase 资源
$ kubectl get oceanbasecluster -A
NAMESPACE NAME AGE
qfusion-admin ob-2db57f43 2d1h
$ kubectl api-resources | grep oceanbase
NAME SHORTNAMES APIGROUP NAMESPACED
oceanbaseclusters obc oceanbase.woqutech.com/v1 true
restores obr oceanbase.woqutech.com/v1 true
三、CRD/CR/Operator 代码级解析
3.1 CRD 定义(YAML → Go 结构体)
实际 CRD 定义
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: oceanbaseclusters.oceanbase.woqutech.com
spec:
group: oceanbase.woqutech.com # API 组名
names:
kind: OceanbaseCluster # Go 结构体类型名
listKind: OceanbaseClusterList
plural: oceanbaseclusters # 复数名
shortNames:
– obc # 缩写
singular: oceanbasecluster # 单数名
scope: Namespaced # 是否命名空间级别
versions:
– name: v1 # API 版本
served: true # 是否通过 API 服务
storage: true # 是否作为存储版本
CRD 对应的 Go 结构体(生成的代码)
package v1
// OceanbaseClusterSpec 定义了期望状态
// +genclient:noStatus
// +kubebuilder:object:generate=true
type OceanbaseClusterSpec struct {
metav1.TypeMeta `json:"metadata"`
// 期望状态:用户定义的配置
AppName string `json:"appName"`
DatabaseBranch DatabaseBranchSpec `json:"databaseBranch"`
IsPaused bool `json:"isPaused"`
// Proxy 配置
Proxy ProxySpec `json:"proxy"`
// Server 配置
Server ServerSpec `json:"server"`
}
// OceanbaseClusterStatus 定义了实际状态
// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:resource:shortname=obc
type OceanbaseClusterStatus struct {
Stage string `json:"stage"`
ParametersStatus ParametersStatus `json:"parametersStatus"`
PauseStage string `json:"pauseStage"`
// Proxy 状态
ProxyStatus ProxyStatus `json:"proxyStatus"`
// Server 状态
ServerStatus ServerStatus `json:"serverStatus"`
// 整体状态
Status ClusterStatus `json:"status,omitempty"`
}
// OceanbaseCluster 是顶层结构体
// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:resource:shortname=obc
type OceanbaseCluster struct {
metav1.TypeMeta `json:"metadata"`
// Spec: 期望状态(用户配置)
Spec OceanbaseClusterSpec `json:"spec"`
// Status: 实际状态(Operator 填写)
Status OceanbaseClusterStatus `json:"status,omitempty"`
}
3.2 CR(Custom Resource)的内存结构
┌─────────────────────────────────────────────────────────────────────┐
│ CR 在内存中的结构 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 对象头 │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ name: ob-2db57f43 │ │ │
│ │ │ namespace: qfusion-admin │ │ │
│ │ │ uid: 1e1d55cc-… │ │ │
│ │ │ labels: │ │ │
│ │ │ AppName: ob-2db57f43 │ │ │
│ │ │ ClusterName: ob-2db57f43 │ │ │
│ │ │ CreatedBy: woqutech.com │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Spec: 期望状态(用户配置) │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ appName: ob-2db57f43 │ │ │
│ │ │ databaseBranch: │ │ │
│ │ │ name: oceanbase-ce │ │ │
│ │ │ version: 4.3.5.3 │ │ │
│ │ │ isPaused: false │ │ │
│ │ │ proxy: │ │ │
│ │ │ replicas: 3 │ │ │
│ │ │ resources: {…} │ │ │
│ │ │ server: │ │ │
│ │ │ replicas: 3 │ │ │
│ │ │ resources: {…} │ │ │
│ │ │ storages: […] │ │ │
│ │ │ zone: […] │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Status: 实际状态(Operator 填写) │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ stage: AlreadyDeployed │ │ │
│ │ │ parametersStatus: │ │ │
│ │ │ proxyApplied: true │ │ │
│ │ │ serverApplied: true │ │ │
│ │ │ proxyStatus: │ │ │
│ │ │ availableReplicas: 3 │ │ │
│ │ │ expectedReplicas: 3 │ │ │
│ │ │ serverStatus: │ │ │
│ │ │ availableReplicas: 3 │ │ │
│ │ │ expectedReplicas: 3 │ │ │
│ │ │ status: │ │ │
│ │ │ permitRollback: false │ │ │
│ │ │ customStatus: available │ │ │
│ │ │ fsmStatus: AC │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
四、调谐循环(Reconcile)代码实现
4.1 完整的 Reconcile Loop 流程图
┌─────────────────────────────────────────────────────────────────────┐
│ OceanBase Operator 完整工作流程 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 【用户操作阶段】 │
│ │
│ 1. 用户编写 YAML 文件:ob-cluster.yaml │
│ 2. kubectl apply -f ob-cluster.yaml │
│ 3. Kubernetes API Server 创建 CR 实例 │
│ │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 【Operator 处理阶段】 │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 持续运行的 Reconcile Loop │ │
│ │ │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ 步骤 1: Watch(监听) │ │ │
│ │ │ ┌─────────────────────────────────────┐ │ │
│ │ │ │ • CR 创建/更新/删除 │ │ │
│ │ │ │ • Pod 状态变化 │ │ │
│ │ │ │ • ConfigMap/Secret 变化 │ │ │
│ │ │ │ • PVC 状态变化 │ │ │
│ │ │ └─────────────────────────────────────┘ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ 步骤 2: 获取期望状态 │ │ │
│ │ │ ┌─────────────────────────────────────┐ │ │
│ │ │ │ 读取 CR.spec │ │ │
│ │ │ │ • topology: 3 zones │ │ │
│ │ │ │ • server.resource.* │ │ │
│ │ │ │ • databaseBranch.version │ │ │
│ │ │ └─────────────────────────────────────┘ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ 步骤 3: 查询实际状态 │ │ │
│ │ │ ┌─────────────────────────────────────┐ │ │
│ │ │ │ kubectl get pods -l app=ob │ │ │
│ │ │ │ kubectl get statefulsets │ │ │
│ │ │ │ kubectl get services │ │ │
│ │ │ │ 连接 OB 集群检查服务 │ │ │
│ │ │ └─────────────────────────────────────┘ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ 步骤 4: 比较 Diff │ │ │
│ │ │ ┌─────────────────────────────────────┐ │ │
│ │ │ │ 期望 vs 实际 │ │ │
│ │ │ │ │ │ │
│ │ │ │ replicas: 3 vs 2 → 扩容 │ │ │
│ │ │ │ version: 4.3 vs 4.2 → 升级 │ │ │
│ │ │ │ pod Crash → 重启 │ │ │
│ │ │ │ storage 100Gi vs 80Gi → 扩容 │ │ │
│ │ │ └─────────────────────────────────────┘ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ 步骤 5: 执行调谐动作 │ │ │
│ │ │ ┌─────────────────────────────────────┐ │ │
│ │ │ │ kubectl apply -f … │ │ │
│ │ │ │ 创建/更新 StatefulSet │ │ │
│ │ │ │ 创建/更新 Service/ConfigMap │ │ │
│ │ │ │ 扩缩容操作 │ │ │
│ │ │ │ 滚动升级 │ │ │
│ │ │ │ 添加/删除 PVC │ │ │
│ │ │ └─────────────────────────────────────┘ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ 步骤 6: 更新 Status │ │ │
│ │ │ ┌─────────────────────────────────────┐ │ │
│ │ │ │ 更新 CR.status.phase │ │ │
│ │ │ │ 更新 CR.status.conditions │ │ │
│ │ │ │ 更新 CR.status.availableReplicas │ │ │
│ │ │ └─────────────────────────────────────┘ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ 步骤 7: 重新入队(持续) │ │ │
│ │ │ ┌─────────────────────────────────────┐ │ │
│ │ │ │ 等待下次事件触发 │ │ │
│ │ │ │ 或定时触发(如 5 分钟) │ │ │
│ │ │ └─────────────────────────────────────┘ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ │ │ │ │
│ └─────────────────────────────────────────────────────┘ │ │
│ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
4.2 Reconcile 函数代码详解
// Operator 的核心 Controller 结构
package controller
import (
ctrl "sigs.k8s.io/controller-runtime"
oceanbasev1 "oceanbase.woqutech.com/api/v1"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
)
// OceanbaseClusterReconciler 是 Operator 的核心
// +kubebuilder:rbac:groups=oceanbase.woqutech.com,resources=oceanbaseclusters,verbs=get;list;watch;create;update;patch;delete
type OceanbaseClusterReconciler struct {
client.Client // Kubernetes 客户端
Scheme *runtime.Scheme // 注册所有相关的类型
Recorder record.EventRecorder // 事件记录器
}
// SetupWithManager 注册 Controller
func (r *OceanbaseClusterReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
Named("oceanbasecluster"). // Controller 名称
For(&oceanbasev1.OceanbaseCluster{}). // 监听的对象类型
Owns(&appsv1.StatefulSet{}). // 拥有的资源类型
Owns(&appsv1.Deployment{}). // 拥有的资源类型
Owns(&corev1.Service{}). // 拥有的资源类型
Owns(&corev1.ConfigMap{}). // 拥有的资源类型
Build(r)
}
// Reconcile 是核心调谐函数
func (r *OceanbaseClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
// req.NamespacedName: ob-2db57f43
// req.Namespace: qfusion-admin
log := log.FromContext(ctx)
log.Info("=== 开始调谐", "name", req.NamespacedName, "namespace", req.Namespace)
obCluster := &oceanbasev1.OceanbaseCluster{}
if err := r.Get(ctx, req.NamespacedName, req.Namespace, obCluster); err != nil {
// CR 被删除了,不做任何操作
return ctrl.Result{}, client.IgnoreNotFound(err)
}
// ===========================================
// 步骤 1: 判断是否需要删除
// ===========================================
if !obCluster.DeletionTimestamp.IsZero() {
log.Info("CR 被标记删除,执行清理")
// 删除关联的所有资源
r.deleteAllResources(ctx, obCluster)
// 移除 finalizer
if err := r.removeFinalizer(ctx, obCluster); err != nil {
return ctrl.Result{}, err
}
return ctrl.Result{}, nil
}
// ===========================================
// 步骤 2: 查询实际状态
// ===========================================
// 2.1 查询 StatefulSet
statefulSet := &appsv1.StatefulSet{}
statefulSetKey := types.NamespacedName{
Namespace: req.Namespace,
Name: fmt.Sprintf("%s-server", req.NamespacedName),
}
if err := r.Get(ctx, statefulSetKey, statefulSet); err != nil {
if !errors.IsNotFound(err) {
return ctrl.Result{}, err
}
// StatefulSet 不存在,需要创建
log.Info("创建 StatefulSet", "replicas", obCluster.Spec.Server.Replicas)
newStatefulSet := r.makeStatefulSet(obCluster)
if err := r.Create(ctx, newStatefulSet); err != nil {
return ctrl.Result{}, err
}
return ctrl.Result{RequeueAfter: 10 * time.Second}, nil
}
// 2.2 查询 Pods(可选,用于详细状态)
podList := &corev1.PodList{}
listOpts := []client.ListOption{
client.MatchingLabels{
"AppName": obCluster.Spec.AppName,
},
client.InNamespace(req.Namespace),
}
if err := r.List(ctx, podList, listOpts…); err != nil {
return ctrl.Result{}, err
}
// ===========================================
// 步骤 3: 比较差异
// ===========================================
// 计算期望的副本数
desiredReplicas := obCluster.Spec.Server.Replicas
actualReplicas := *statefulSet.Spec.Replicas
// 判断需要什么操作
var action string
if actualReplicas != desiredReplicas {
if desiredReplicas > actualReplicas {
// 需要扩容
action = "扩容"
statefulSet.Spec.Replicas = &desiredReplicas
log.Info("扩容 StatefulSet", "from", actualReplicas, "to", desiredReplicas)
} else {
// 需要缩容
action = "缩容"
statefulSet.Spec.Replicas = &desiredReplicas
log.Info("缩容 StatefulSet", "from", actualReplicas, "to", desiredReplicas)
}
// 执行更新
if err := r.Update(ctx, statefulSet); err != nil {
return ctrl.Result{}, err
}
} else {
action = "无操作"
}
// ===========================================
// 步骤 4: 更新 Service
// ===========================================
if err := r.ensureServices(ctx, obCluster); err != nil {
return ctrl.Result{}, err
}
// ===========================================
// 步骤 5: 更新 ConfigMap
// ===========================================
if err := r.ensureConfigMaps(ctx, obCluster); err != nil {
return ctrl.Result{}, err
}
// ===========================================
// 步骤 6: 更新 CR Status
// ===========================================
// 6.1 更新 ServerStatus
obCluster.Status.ServerStatus.AvailableReplicas = actualReplicas
obCluster.Status.ServerStatus.ExpectedReplicas = desiredReplicas
// 6.2 更新 ProxyStatus
proxyPodList := &corev1.PodList{}
proxyListOpts := []client.ListOption{
client.MatchingLabels{
"AppName": fmt.Sprintf("%s-proxy", obCluster.Spec.AppName),
},
client.InNamespace(req.Namespace),
}
if err := r.List(ctx, proxyPodList, proxyListOpts…); err == nil {
obCluster.Status.ProxyStatus.AvailableReplicas = len(proxyPodList.Items)
obCluster.Status.ProxyStatus.ExpectedReplicas = obCluster.Spec.Proxy.Replicas
}
// 6.3 更新阶段
if actualReplicas == desiredReplicas {
obCluster.Status.Stage = "Running"
} else {
obCluster.Status.Stage = "Updating"
}
// 6.4 执行更新
if err := r.Status().Update(ctx, obCluster); err != nil {
log.Error("更新 Status 失败", "error", err)
return ctrl.Result{}, err
}
log.Info("调谐完成", "action", action, "replicas", actualReplicas)
// ===========================================
// 步骤 7: 返回结果,决定下次何时再次调谐
// ===========================================
if obCluster.Spec.IsPaused {
// 暂停状态,不重新入队
log.Info("集群已暂停,不继续调谐")
return ctrl.Result{}, nil
}
// 正常情况,30 秒后再次调谐
return ctrl.Result{RequeueAfter: 30 * time.Second}, nil
}
五、状态机(State Machine)与事件
5.1 Operator 状态机
// 集群状态机定义
type ClusterPhase string
const (
// ================================
// 等待状态
// ================================
PhasePending ClusterPhase = "Pending" // 等待创建资源
PhaseCreating ClusterPhase = "Creating" // 正在创建资源
// ================================
// 运行状态
// ================================
PhaseRunning ClusterPhase = "Running" // 正常运行
PhaseUpgrading ClusterPhase = "Upgrading" // 正在升级
PhaseScaling ClusterPhase = "Scaling" // 正在扩缩容
// ================================
// 错误状态
// ================================
PhaseFailed ClusterPhase = "Failed" // 创建/更新失败
PhaseDegraded ClusterPhase = "Degraded" // 部分故障
)
// 状态转换规则
var stateTransitions = map[ClusterPhase][]ClusterPhase{
PhasePending: {PhaseCreating, PhaseFailed},
PhaseCreating: {PhaseRunning, PhaseFailed},
PhaseRunning: {PhaseScaling, PhaseUpgrading, PhaseDegraded, PhaseFailed},
PhaseScaling: {PhaseRunning, PhaseDegraded, PhaseFailed},
PhaseUpgrading: {PhaseRunning, PhaseDegraded, PhaseFailed},
PhaseDegraded: {PhaseRunning, PhaseFailed},
PhaseFailed: {}, // 终态
}
5.2 状态机流程图
┌─────────────────────────────────────────────────────────────┐
│ Operator 状态机 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌────┐ │
│ │ Pending │ │
│ └─┬─┘ │
│ │ │
│ ├──▶ Creating │
│ │ │ │
│ │ └─┬─┘ │
│ │ ┌──────────┐ │
│ │ │ Running │ │
│ │ └─┬───┬───┬──────────┐ │
│ │ │ │ │ └──┬────┘ │
│ │ ▼ ▼ ▼ ▼ │
│ │ Scaling Upgrading Degraded │
│ │ │ │ │ └─┬───────┘ │
│ │ │ │ │ ▼ │
│ │ └─────┴────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ ▼ Failed
│ │ │
└─────────────────────────────────────────────────────┘
5.3 Watch 事件驱动机制
// Watch 事件类型定义
const (
// ================================
// CR 事件(用户操作)
// ================================
EventAdded EventType = "Added" // CR 被创建
EventUpdated EventType = "Updated" // CR 被更新
EventDeleted EventType = "Deleted" // CR 被删除
// ================================
// 关联资源事件(系统状态变化)
// ================================
PodAdded EventType = "PodAdded" // Pod 创建
PodReady EventType = "PodReady" // Pod Ready
PodNotReady EventType = "PodNotReady" // Pod NotReady
PodDeleted EventType = "PodDeleted" // Pod 删除
)
// Watch 处理逻辑(伪代码)
func (r *OceanbaseClusterReconciler) setupWatch(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&oceanbasev1.OceanbaseCluster{}). // 监听 CR 变更
// 关联资源 Watch
Owns(&appsv1.StatefulSet{}). // 监听拥有的 StatefulSet
Owns(&appsv1.Deployment{}). // 监听拥有的 Deployment
Owns(&corev1.Service{}). // 监听拥有的 Service
Owns(&corev1.ConfigMap{}). // 监听拥有的 ConfigMap
// 设置事件处理器
WithEventFilter(r.podFilter). // 过滤 Pod 事件
WithEventFilter(r.serviceFilter). // 过滤 Service 事件
Build(r)
}
// 事件过滤示例
func (r *OceanbaseClusterReconciler) podFilter(eventObj client.Object) bool {
pod, ok := eventObj.(*corev1.Pod)
if !ok {
return true
}
// 只关心属于当前集群的 Pod
return pod.Labels["AppName"] == r.currentAppName
}
六、OceanBase 实战案例
6.1 实际环境信息(脱敏)
| 目标环境 | 生产环境 Kubernetes 集群 |
| 数据库标识 | ob-2db57f43 |
| Operator | OceanBase ob-operator (database-operator) |
| 命名空间 | qfusion-admin |
6.2 验证步骤与实际输出
# 1. 查看已注册的 OceanBase CRD
$ kubectl get crd | grep oceanbase
NAME CREATED AT
oceanbaseclusters.oceanbase.woqutech.com 2026-01-22T04:19:53Z
restores.oceanbase.woqutech.com 2026-01-22T04:19:53Z
# 2. 查看已部署的 OceanbaseCluster 实例
$ kubectl get oceanbasecluster -A
NAMESPACE NAME AGE
qfusion-admin ob-2db57f43 2d1h
# 3. 查看 OceanBase 相关 Pods
$ kubectl get pods -n qfusion-admin | grep ob-2db57f43
NAME READY STATUS AGE
ob-2db57f43-obproxy-0-0 1/1 Running 47h
ob-2db57f43-obproxy-1-0 1/1 Running 47h
ob-2db57f43-obproxy-2-0 1/1 Running 47h
ob-2db57f43-observer-obzone1-0-0 2/2 Running 47h
ob-2db57f43-observer-obzone2-0-0 2/2 Running 47h
ob-2db57f43-observer-obzone3-0-0 2/2 Running 47h
6.3 集群架构拓扑
OceanBase 集群架构图
OceanBase Operator (database-operator)
监听 OceanbaseCluster CR 变化
调谐集群状态
▼
Proxy 层 (OBProxy) – 3副本
ob-2db57f43-obproxy-0-0 (Pod IP)
ob-2db57f43-obproxy-1-0 (Pod IP)
ob-2db57f43-obproxy-2-0 (Pod IP)
Port: 2883 (SQL), 2884 (RPC)
▼
Observer 层 – 3 Zone
Zone 1: obzone1 Zone 2: obzone2
┌───────────────────┐ ┌───────────────────┐
│ observer Pod │ │ observer Pod │
│ Port: 2881/2882 │ │ Port: 2881/2882 │
└───────────────────┘ └───────────────────┘
Zone 3: obzone3
┌───────────────────┐
│ observer Pod │
│ Port: 2881/2882 │
└───────────────────┘
Region: shanghai
Storage: 26Gi datafile + 26Gi datalog per zone
6.4 集群配置参数说明
| 数据库版本 | oceanbase-ce | 4.3.5.3 | |
| Proxy 副本数 | replicas | 3 | |
| Proxy CPU | limits | 2 核 | |
| Proxy 内存 | limits | 4Gi | |
| Server CPU | cpu_count | 4 核 | |
| Server 内存 | memory_limit | 8Gi | |
| Datafile 大小 | datafile_size | 20G | |
| Log Disk 大小 | log_disk_size | 20G | |
| System Memory | system_memory | 3G | |
| 存储类 | StorageClass | csi-localpv | |
| 区域 | Region | shanghai | |
| 分区 | Zone | obzone1, obzone2, obzone3 |
七、通用学习指南
7.1 学习任何 Operator 的六步法
当你遇到任何新的 Operator 时,按照以下步骤学习:
步骤 1: 找 CRD
kubectl get crd | grep <app-name>
kubectl describe crd <crd-name>
kubectl get crd <crd-name> -o yaml
步骤 2: 看结构 Schema
kubectl explain <cr-name>
kubectl explain <cr-name>.spec
kubectl explain <cr-name>.status
步骤 3: 看实例 CR
kubectl get <cr-name> -A
kubectl get <cr-name> <instance-name> -o yaml
kubectl describe <cr-name> <instance-name>
步骤 4: 理解状态 status
关注 status 下的字段:
• phase – 当前阶段
• conditions – 健康检查条件
• availableReplicas – 可用副本数
• observedGeneration – 已处理的配置代次
步骤 5: 看 Operator 日志
kubectl get pods -n <operator-namespace> -l app=<operator-name>
kubectl logs -n <operator-namespace> -l app=<operator-name> -f
步骤 6: 看关联资源
kubectl get all -l app=<cr-name>
7.2 主流数据库 Operator 对比
| MySQL | mysqlclusters.mysql.com | MySQL Operator | 集群管理、备份、高可用 |
| PostgreSQL | postgresclusters.postgresql.org | Zalando Postgres Operator | 集群管理、备份、版本升级 |
| MongoDB | mongodbcommunity.mongodb.com | MongoDB Atlas Operator | 分片集群、备份 |
| Redis | redis.redis.io | Redis Operator | 集群管理、持久化、哨兵模式 |
| Kafka | kafka.strimzi.io | Strimzi Kafka Operator | 主题管理、消费者组、连接器 |
| Elasticsearch | elasticsearch.k8s.elastic.co | Elasticsearch Operator | 节点管理、索引生命周期 |
| Prometheus | monitoring.coreos.com | Prometheus Operator | Prometheus、Alertmanager、Thanos |
| OceanBase | oceanbaseclusters.oceanbase.woqutech.com | ob-operator | 集群管理、Proxy、Observer 管理 |
| TiDB | tidbclusters.pingcap.com | TiDB Operator | 分布式数据库管理 |
| RabbitMQ | rabbitmqclusters.rabbitmq.com | RabbitMQ Cluster Operator | 消息队列集群 |
7.3 Operator 开发框架对比
| Kubebuilder | 官方推荐,生成代码量少 | 大多数 Operator 开发 |
| Operator SDK | 官方 SDK,简化开发 | 需要 Webhook 的 Operator |
| KUDO | 声明式编程,不需要写 Go | 快速开发简单 Operator |
| Headlamp | 可视化 Operator 管理 | 需要 UI 的场景 |
| OAM | Kubernetes 标准应用模型 | 需要应用模型的复杂系统 |
附录:快速参考
A. kubectl api-resources 命令详解
# 列出所有 API 资源
kubectl api-resources
# 列出所有资源,显示额外信息
kubectl api-resources -o wide
# 列出特定资源组的资源
kubectl api-resources –api-group=oceanbase.woqutech.com
# 查看 CRD 详情
kubectl get crd
# 解释 CRD 结构
kubectl explain oceanbasecluster
kubectl explain oceanbasecluster.spec
kubectl explain oceanbasecluster.status
B. 常用调试命令
# 查看 OceanBase 相关 CRD
kubectl get crd | grep oceanbase
# 查看所有 OceanbaseCluster 实例
kubectl get oceanbasecluster -A
# 查看特定 OceanbaseCluster 详情
kubectl describe oceanbasecluster <name> -n <namespace>
# 查看 OceanbaseCluster YAML
kubectl get oceanbasecluster <name> -n <namespace> -o yaml
# 编辑 OceanbaseCluster
kubectl edit oceanbasecluster <name> -n <namespace>
# 删除 OceanbaseCluster
kubectl delete oceanbasecluster <name> -n <namespace>
# 查看 Operator 日志
kubectl logs -n <operator-namespace> -l app=<operator-name> -f
# 查看 CR 变化事件
kubectl get events -n <namespace> –field-selector involvedObject.kind=OceanbaseCluster
C. 术语对照表
| 自定义资源定义 | Custom Resource Definition | CRD | apiextensions.k8s.io/v1.CustomResourceDefinition |
| 自定义资源 | Custom Resource | CR | v1alpha1.OceanbaseCluster{} |
| 操作器/运算符 | Operator | – | controller-runtime.Controller |
| 调谐循环 | Reconcile Loop | – | func Reconcile(…) ctrl.Result |
| 期望状态 | Desired State | – | cr.Spec |
| 实际状态 | Actual State | – | 实际运行的 Pod/StatefulSet 状态 |
| 控制器 | Controller | – | 实现 Reconcile 逻辑的组件 |
| 工作队列 | WorkQueue | – | workqueue.RateLimitingInterface |
| 事件过滤 | Event Filter | – | WithEventFilter() |
| 最终保护器 | Finalizer | – | cr.Finalizers[] |
| 观察代次 | Observed Generation | – | cr.Status.ObservedGeneration |
报告生成日期: 2026-03-05
参考资料:
- Kubernetes CRD 官方文档
- Kubernetes Operator 模式文档
- Kubebuilder 文档
- Controller Runtime 文档
- OceanBase ob-operator 仓库
