2. Kubernetes Operator 架构回顾:CRD、Controller、Reconciler、Webhook 的核心职责

在深入 SLO 违约后的资源边界处置之前,必须重新梳理 Operator 的四大核心组件:CRD(Custom Resource Definition)、Controller、Reconciler 和 Webhook。它们共同构成了 Operator 的控制面蓝图,任何一环的失效都会直接导致 SLO 违约。

2.1 四组件职责总览

组件 核心职责 与 SLO 违约的关联
CRD 定义自定义资源的 Schema(结构、校验、版本) Schema 缺陷导致资源创建失败或状态不一致
Controller 监听资源变化,维护控制循环(Informer + WorkQueue) 监听中断或队列积压导致状态滞后
Reconciler 执行期望状态到实际状态的调和逻辑 调和失败或死循环引发资源边界漂移
Webhook 拦截 API 请求,执行准入校验/默认值注入 Webhook 超时或崩溃阻塞整个 API 链路

2.2 CRD:资源定义的基石

CRD 是 Operator 的“数据契约”。它定义了自定义资源的 OpenAPI v3 Schema,包括必填字段、类型约束、枚举值以及版本转换规则。一个典型的 CRD 声明如下:

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: databases.example.com
spec:
  group: example.com
  names:
    kind: Database
    plural: databases
  scope: Namespaced
  versions:
    - name: v1
      served: true
      storage: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                engine:
                  type: string
                  enum: ["mysql", "postgres"]
                replicas:
                  type: integer
                  minimum: 1
                  maximum: 10
SRE 视角: CRD 的 preserveUnknownFields: false 和 pruning 行为直接影响资源边界的稳定性。未定义的字段被静默丢弃,可能导致 Reconciler 读取到不完整的 spec,进而触发 SLO 违约。

2.3 Controller:控制循环的引擎

Controller 负责驱动整个控制循环。它通过 Informer 监听 CRD 实例的变化,将事件推入 WorkQueue,再由 Reconciler 消费。核心流程如下:

  1. List & Watch:Informer 向 API Server 发起初始 List 请求,随后建立长连接 Watch 增量事件。
  2. Delta FIFO 去重:相同资源的多次变更在队列中合并为一次,避免重复调和。
  3. WorkQueue 重试:失败的事件会以指数退避方式重新入队,默认最多重试 10 次。
常见故障模式: Informer 与 API Server 之间的 Watch 连接因网络抖动断开后,Controller 会触发全量 Re-list。如果 CRD 实例数量超过 10 万,Re-list 期间的资源状态将完全不可用,直接导致 SLO 违约。

2.4 Reconciler:状态调和的执行者

Reconciler 是 Operator 的业务逻辑核心。它接收 WorkQueue 中的请求,对比 期望状态(Spec) 与 实际状态(Status),然后执行创建、更新、删除操作。一个标准的 Reconciler 方法签名如下:

func (r *DatabaseReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    // 1. 获取 CR 实例
    db := &examplev1.Database{}
    if err := r.Get(ctx, req.NamespacedName, db); err != nil {
        return ctrl.Result{}, client.IgnoreNotFound(err)
    }

    // 2. 获取当前实际状态(例如 Pod 数量)
    currentReplicas := r.getCurrentReplicas(db)

    // 3. 调和:调整 Deployment 的副本数
    if currentReplicas != db.Spec.Replicas {
        r.scaleDeployment(db, db.Spec.Replicas)
    }

    // 4. 更新状态
    db.Status.ReadyReplicas = db.Spec.Replicas
    r.Status().Update(ctx, db)

    return ctrl.Result{RequeueAfter: 30 * time.Second}, nil
}
关键指标: Reconciler 的调和延迟(Reconcile Latency)是 SLO 的核心观测点。如果单次调和超过 5 秒,且队列深度持续增长,说明资源边界正在失控。

2.5 Webhook:准入控制的守门员

Webhook 在资源写入 etcd 之前拦截请求,分为 MutatingWebhook(修改资源)和 ValidatingWebhook(校验资源)。它们直接决定了哪些资源可以进入系统:

  • MutatingWebhook:注入默认值(如默认存储类、默认副本数),确保 Spec 的完整性。
  • ValidatingWebhook:校验业务规则(如引擎类型是否支持、副本数是否在配额内),拒绝非法请求。
// ValidatingWebhook 示例:拒绝副本数超过 10 的请求
func (v *DatabaseValidator) ValidateCreate(ctx context.Context, obj runtime.Object) error {
    db := obj.(*examplev1.Database)
    if db.Spec.Replicas > 10 {
        return fmt.Errorf("replicas cannot exceed 10")
    }
    return nil
}
SLO 违约场景: Webhook 服务崩溃后,API Server 会进入 Fail 策略(默认),所有涉及该 CRD 的写操作全部失败。如果 Webhook 配置了 failurePolicy: Ignore,则非法资源可能绕过校验直接写入,导致 Reconciler 处理异常状态。

2.6 四组件协作关系图

下图展示了 Operator 控制面中 CRD、Controller、Reconciler、Webhook 之间的数据流与调用链:

Operator 控制面四组件协作架构 API Server Webhook (Mutate/Validate) CRD (Schema 定义) Controller (Informer+Queue) Reconciler (调和逻辑) etcd (持久化) 数据流说明: 1. 用户提交 CR 实例 → API Server → Webhook(校验/注入)→ etcd 持久化 2. Controller 的 Informer 通过 Watch 感知 etcd 中的资源变化 → 入队 WorkQueue 3. Reconciler 消费队列 → 读取 CRD Schema 定义的 Spec → 执行调和 → 回写 Status 4. 任何组件故障(Webhook 超时、Informer 断连、Reconciler 死循环)都会导致 SLO 违约

2.7 组件故障与 SLO 违约映射

下表总结了每个组件在故障状态下对 SLO 的具体影响:

组件 故障模式 SLO 违约表现 恢复手段
CRD Schema 版本不兼容 资源无法创建/更新,API 错误率上升 回滚 CRD 版本,或执行存储迁移
Controller Informer Watch 断开 资源状态长时间不更新 重启 Controller Pod,触发 Re-list
Reconciler 调和死循环 API Server 负载飙升,资源版本频繁变更 注入调和断路器,限制重试次数
Webhook 服务不可用 写操作全部失败(Fail 策略)或非法资源写入(Ignore 策略) 水平扩展 Webhook 实例,配置超时熔断