2. Operator 模式概述:Operator 设计模式、CRD 与 Controller 的交互流程
Operator 是 Kubernetes 生态中实现“应用感知”自动化运维的核心设计模式。它将运维人员对特定应用(如数据库、消息队列、监控系统)的领域知识编码为软件,通过扩展 Kubernetes API 来管理复杂的有状态应用。理解 Operator 模式,是掌握 RBAC Operator 控制器调试的前提。
2.1 Operator 设计模式的核心思想
Operator 模式本质上是一种 “控制循环 + 声明式 API” 的工程实践。它借鉴了 Google 在 Borg 中的经验,将运维专家对应用生命周期管理的操作(扩缩容、备份、升级、故障恢复)转化为 Kubernetes 原生的资源对象和控制器逻辑。
| 维度 | 传统运维 | Operator 模式 |
|---|---|---|
| 操作方式 | SSH 登录、手动执行脚本、人工巡检 | 声明式 YAML 提交、自动调谐、事件驱动 |
| 状态管理 | 依赖 CMDB 或运维人员记忆 | 通过 CRD 存储在 etcd 中,作为唯一事实来源 |
| 故障恢复 | 人工介入、告警响应 | 控制器自动检测期望状态与实际状态偏差并修复 |
| 扩展性 | 依赖特定工具链(Ansible、Puppet) | 原生集成 Kubernetes API,复用 RBAC、调度、网络能力 |
2.2 CRD(Custom Resource Definition)—— 定义你的应用模型
CRD 是 Operator 模式的“数据面”。它允许你在 Kubernetes 中定义新的资源类型,例如 RedisCluster、PostgreSQLInstance 或 RBACRoleBindingSet。一旦 CRD 被注册到集群,你就可以像使用原生 Pod、Service 一样,通过 kubectl 创建、查询和删除这些自定义资源。
一个典型的 CRD 定义包含以下关键字段:
- group:API 组,用于资源分类,例如
rbac.example.com。 - names:资源名称定义,包括
plural(复数)、singular(单数)、kind(类型名)和shortNames(短名称)。 - scope:作用域,
Namespaced(命名空间级别)或Cluster(集群级别)。 - versions:API 版本列表,每个版本下包含
schema(结构定义,通常使用 OpenAPI v3 规范)。
# 一个简化的 RBAC 绑定集 CRD 示例
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: rbacbindingsets.rbac.example.com
spec:
group: rbac.example.com
names:
kind: RBACBindingSet
listKind: RBACBindingSetList
plural: rbacbindingsets
singular: rbacbindingset
shortNames:
- rbs
scope: Namespaced
versions:
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
subjects:
type: array
items:
type: object
properties:
kind:
type: string
name:
type: string
roleRef:
type: object
properties:
apiGroup:
type: string
kind:
type: string
name:
type: string
schema 是第一个检查点。如果用户提交的 YAML 字段名拼写错误或类型不匹配,API Server 会直接拒绝请求,而不会触发 Controller 逻辑。使用 kubectl explain rbacbindingset 可以快速查看 CRD 的字段结构。
2.3 Controller(控制器)—— 实现你的运维逻辑
Controller 是 Operator 模式的“控制面”。它是一个持续运行的循环(Reconciliation Loop),负责监听 CRD 实例的变化,并采取行动使集群的实际状态趋近于 CRD 中声明的期望状态。
Controller 的核心工作流程通常包含以下步骤:
- 监听(Watch):通过 Informer 机制监听 CRD 实例的创建、更新、删除事件。
- 入队(Enqueue):将事件对应的资源对象键(Namespace/Name)放入工作队列。
- 调谐(Reconcile):从队列中取出键,获取最新的 CRD 实例,读取
spec(期望状态)。 - 对比(Diff):查询集群中当前存在的相关资源(如 ServiceAccount、RoleBinding、Deployment),与期望状态进行对比。
- 执行(Act):创建、更新或删除 Kubernetes 资源,使实际状态与期望状态一致。
- 更新状态(Update Status):将操作结果(成功/失败、当前版本、健康状态)写回 CRD 的
status字段。
2.4 CRD 与 Controller 的交互流程(核心图示)
下图展示了从用户提交 CRD 实例到 Controller 完成调谐的完整数据流:
2.5 交互流程的关键机制:Informer 与工作队列
在 Controller 内部,Informer 和 工作队列 是两个至关重要的组件,它们决定了 Controller 的性能和可靠性。
| 组件 | 职责 | 调试关注点 |
|---|---|---|
| Informer | 通过 List & Watch 机制与 API Server 保持长连接,将 CRD 实例缓存在本地内存中,避免每次调谐都请求 API Server。 | Informer 的 ResyncPeriod 设置是否合理?缓存是否与 etcd 一致? |
| 工作队列 | 使用 workqueue.RateLimitingQueue 实现,提供去重、限速、重试机制。当 Reconciler 处理失败时,会将键重新入队并等待指数退避后重试。 |
队列深度是否持续增长?重试次数是否过多?是否存在死循环? |
ResyncPeriod 配置。如果设置为 0,Informer 将不会定期重新同步,导致 Controller 只能感知到事件驱动的变更。当 API Server 与 Informer 缓存出现偏差时(例如网络闪断导致 Watch 事件丢失),Controller 将无法自动修复。建议在生产环境中设置合理的 ResyncPeriod(如 10 分钟)。
2.6 从 Operator 模式到 RBAC 控制器
在本课程中,我们将构建一个 RBAC 绑定集控制器。它的 CRD 定义了一个 RBACBindingSet 资源,用户只需声明“哪些主体(User/Group/ServiceAccount)应该拥有哪些角色(Role/ClusterRole)”,Controller 就会自动创建、更新或删除对应的 RoleBinding 或 ClusterRoleBinding。
这种模式的优势在于:
- 声明式管理:运维人员不再需要逐个管理成百上千个 RoleBinding,只需维护一个
RBACBindingSet实例。 - 一致性保障:Controller 会持续调谐,确保集群中的实际绑定关系与 CRD 定义完全一致,手动修改会被自动覆盖。
- 审计友好:所有 RBAC 配置的变更历史都可以通过 CRD 的
status字段和 Kubernetes 事件追溯。