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 消费。核心流程如下:
- List & Watch:Informer 向 API Server 发起初始 List 请求,随后建立长连接 Watch 增量事件。
- Delta FIFO 去重:相同资源的多次变更在队列中合并为一次,避免重复调和。
- 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 之间的数据流与调用链:
2.7 组件故障与 SLO 违约映射
下表总结了每个组件在故障状态下对 SLO 的具体影响:
| 组件 | 故障模式 | SLO 违约表现 | 恢复手段 |
|---|---|---|---|
| CRD | Schema 版本不兼容 | 资源无法创建/更新,API 错误率上升 | 回滚 CRD 版本,或执行存储迁移 |
| Controller | Informer Watch 断开 | 资源状态长时间不更新 | 重启 Controller Pod,触发 Re-list |
| Reconciler | 调和死循环 | API Server 负载飙升,资源版本频繁变更 | 注入调和断路器,限制重试次数 |
| Webhook | 服务不可用 | 写操作全部失败(Fail 策略)或非法资源写入(Ignore 策略) | 水平扩展 Webhook 实例,配置超时熔断 |