想象一下,你要开一家特色餐厅。传统的 Kubernetes 就像一家标准化快餐连锁店——前台、后厨、仓库、收银台都是总部统一配置好的,你只能在固定的菜单框框里点菜。但如果你想把餐厅开成“可以自己定义招牌菜”的私房菜馆呢?这时就需要两样东西:一张空白的“自定义菜单模板”(CRD),以及一位“自动执行菜谱的大厨”(Operator)。这位大厨不仅知道怎么把菜端上桌,还懂得时刻盯着后厨——菜凉了重新加热、食材不够了自动补货、火候不对了立即调整。Kubebuilder 就是帮你快速招募并训练这位大厨的“厨师学校”——你只需写下“招牌菜的规则”,它就把大厨的雇佣、培训、上岗流程全部自动化。 本文将带你从零开始,理解 CRD 如何定义你的“专属菜单”,Operator 如何扮演“自动巡场的餐厅经理”,以及如何使用 Kubebuilder 这套脚手架工具,快速开发出属于你自己的 Kubernetes“智能餐厅”。文中会引入 controller 的协调循环(Reconcile Loop)——就像大厨每时每刻都在问“现实和理想差多少?”——以及与 API 服务器的交互、Webhook 的“门卫校验”等概念。

岗位关联

对 AI 从业者而言,掌握 CRD 与 Operator 开发意味着你能把 AI 模型的训练、部署、扩缩容等复杂生命周期管理“产品化”为 Kubernetes 上的自助服务——这是云原生 AI 平台工程师的核心技能,也是从“能用”到“好用”的分水岭。

目录
  1. 可视化演示
  2. 问题与核心思想
  3. CRD自定义资源
  4. Operator运行模式
  5. Kubebuilder脚手架
  6. Reconcile协调循环
  7. Webhook准入校验
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

展示Kubernetes Operator Reconcile控制循环、CRD资源管理结构及Operator方案对比的三模态交互动画。

本节配有交互动效(进入视口后自动加载,约 3KB)。

Reconcile控制循环 Watch Diff Reconcile→desired 控制器Watch资源变化对比期望与实际状态执行操作使系统收敛到期望状态

问题与核心思想

你开了一家私房菜馆,但总部的“标准化套餐”只有 5 种固定菜品——就像 Kubernetes 原生只提供 Pod、Service、Deployment 等有限的几种资源类型。你想推出自己的招牌菜“AI 训练套餐”,却发现总部菜单上根本没有这一项。这就是原生资源局限:Kubernetes 的 API 能力边界由内置资源划定,超出范围的业务需求无法直接表达。CRD(自定义资源定义)就是那张空白的“专属菜单模板”——你在上面刻下自己的菜品规格(字段),Kubernetes 就把它当作一级公民资源来管理。

更进一步,如果你只是把新菜写进菜单而不培训厨师,那菜单仍是摆设。这正是 Operator 的用武之地:它像一位“全自动大厨”,随时对照菜单(期望状态)检查后厨实际情况(现实状态),发现偏差立即纠正——菜品凉了重新加热、缺了食材自动补货。这种“声明式 API + 自动化闭环”就是 Kubernetes 扩展生态的核心思想。

核心思想模型:

回到餐厅的比喻:CRD 给了你一张空白菜单页,Operator 给了你一位时刻在岗的大厨。你只需写下“三小时后上这道菜”,剩下的一切——备料、烹饪、摆盘、上桌——都由大厨自动完成。这就是云原生时代管理复杂业务系统的方式。

CRD+Operator=自定义业务资源的声明式管理闭环\displaystyle CRD + Operator = 自定义业务资源的声明式管理闭环
这个等式告诉我们:CRD 负责“定义是什么”(扩展 API),Operator 负责“保证做成”(实现自动化)。二者结合,就能把任意领域业务(AI 训练、数据库、消息队列)变成 Kubernetes 原生体验。
  1. CRD 扩展动作CRD 向 Kubernetes API 服务器注册一个新的资源类型,相当于新增一种“菜谱模板”
    CRD:定义新资源类型→API Server 可识别CRD: \text{定义新资源类型} \rightarrow \text{API Server 可识别}
  2. Operator 自动化操作Operator 内含控制器,对 CRD 实例执行“期望-现实”比对与调整
    Operator:控制器↔CRD 实例→子资源管理Operator: \text{控制器} \leftrightarrow \text{CRD 实例} \rightarrow \text{子资源管理}
  3. 闭环形成机制用户只需声明“我要什么”,系统自动完成“怎么做到”
    用户声明→CRD实例→Operator调谐→现实=期望用户声明 \rightarrow CRD 实例 \rightarrow Operator 调谐 \rightarrow 现实=期望

CRD自定义资源

菜单模板上要设计哪些栏目?这就是 CRD 的 Schema 字段定义。一份典型的 CRD 包含三个核心区域:metadata(餐桌号、下单时间——资源的身份信息)、spec(菜品规格——用户声明的期望状态)、status(出餐状态——系统的实际反馈)。以 AI 训练任务为例,spec 里可以定义模型名称、训练数据路径、GPU 数量、学习率等参数;status 里则记录当前训练阶段、已运行 epoch 数、最新 loss 值。

定义一个 CRD 的 YAML 骨架如下:

版本与兼容策略:就像餐厅菜单改版时要保留老顾客熟悉的旧菜品一样,CRD 也支持多版本并存。新版本用 conversion 策略兼容旧版本,常用 Webhook 转换方式在 v1 和 v1beta1 之间转换字段,保证旧客户端不受影响。

1. group 分组:定义资源所属的 API 组,类似餐厅的“菜单系列”命名空间

group:ai.example.com\text{group}: ai.example.com

2. version 版本:声明资源的版本列表,其中 storage: true 表示持久化存储用此版本

v1:registry→storagev1: \text{registry} \rightarrow \text{storage}

3. openAPIV3Schema 校验:声明字段的类型与约束,不符合 Schema 的请求会被 API Server 直接拒绝

spec:{modelName,gpuCount}⇒JSON Schema 校验\text{spec}: \{ \text{modelName}, \text{gpuCount} \} \Rightarrow \text{JSON Schema 校验}

4. names 命名:定义资源的复数名、单数名、Kind 名,如同给菜品起多个别名方便点单

plural:aijobs,kind:AIJob\text{plural}: \text{aijobs}, \text{kind}: \text{AIJob}

CRD 设计是 Operator 开发的地基。就像私房菜馆的招牌菜之所以成功,靠的是一份精心设计的菜单——字段定义清晰、校验规则严格、版本演进有序,后续的“大厨”(Operator)才有据可依。

yaml28 行
apiVersion: apiextensions.k8s.io/v1kind: CustomResourceDefinitionmetadata:  name: aijobs.ai.example.comspec:  group: ai.example.com  versions:    - name: v1      served: true      storage: true      schema:        openAPIV3Schema:          type: object          properties:            spec:              type: object              properties:                modelName: { type: string }                gpuCount: { type: integer }            status:              type: object              properties:                phase: { type: string }  scope: Namespaced  names:    plural: aijobs    singular: aijob    kind: AIJob

Operator运行模式

菜单设计好了,谁来照着做菜?Operator 模式的核心思想,是将某个领域专家(比如 AI 平台工程师)的运维知识固化到一个自动化控制器中。这个控制器持续观察集群中的 CRD 实例,然后创建或调整相关的子资源(如 Pod、Service、PVC),让现实一步步逼近用户声明的期望状态。

一个典型的 Operator 逻辑链:

这便是控制器模式的核心。以训练 AI 模型为例:用户在 AIJob 里声明“用 4 块 GPU 跑 ResNet50”,Operator 看到后自动创建对应 GPU Pod;当某个 Pod 崩溃时,Operator 监测到现实数量小于期望数量,立即重新创建。这种“自定义业务闭环”正是 Kubernetes 从“容器编排平台”升级为“任意工作负载管理平台”的关键。

Watch(CRD)→事件触发Reconcile(期望状态, 现实状态)→资源操作子资源调谐\displaystyle \text{Watch}(CRD) \xrightarrow{\text{事件触发}} \text{Reconcile(期望状态, 现实状态)} \xrightarrow{\text{资源操作}} \text{子资源调谐}
  1. Watch 监听动作Operator 监听 CRD 的增删改事件,如同大厨注意客人点单的铃声
    informer.Watch(AIJob)→add/update/delete Event进入队列\text{informer.Watch}(\text{AIJob}) \xrightarrow{\text{add/update/delete Event}} \text{进入队列}
  2. Reconcile 调谐动作从队列取出事件,读取当前 CR 对象,与集群现实状态对比
    Reconcile(r,CR实例)→δ=期望−现实\text{Reconcile}(r, \text{CR实例}) \rightarrow \delta = \text{期望} - \text{现实}
  3. 子资源操作动作根据差异创建/更新/删除 Pod 等资源,然后重新入队等待下次调谐
    δ≠0⇒创建/更新 Pod→状态更新重新入队\delta \neq 0 \Rightarrow \text{创建/更新 Pod} \xrightarrow{\text{状态更新}} \text{重新入队}

Kubebuilder脚手架

每次开私房菜馆都要从搬砖砌墙开始吗?Kubebuilder 是 Kubernetes SIG 官方推荐的脚手架工具,类似“厨师培训学校”——它把 Operator 开发的繁琐步骤标准化,让你聚焦核心业务逻辑。

搭建一个新项目:

生成的项目结构:

开发工作流:修改 aijob_types.go 中的 AIJobSpec 与 AIJobStatus 结构体 → 执行 make generate 自动生成 deepcopy 方法与 CRD 清单 → 执行 make manifests 生成 RBAC 与 CRD YAML → 在 controllers/aijob_controller.go 中编写 Reconcile 逻辑 → make install 将 CRD 安装进集群 → make run 本地启动 Operator 调试。

这就像厨师学校提供了标准化的厨房布局和工具清单,你只需要专心研究“招牌菜的做法”,而不必纠结灶台怎么砌、烟囱怎么搭。Kubebuilder 的 make 命令体系将构建、测试、部署全部自动化,让 Operator 开发规模化、可复制。

bash4 行
# 初始化项目kubebuilder init --domain ai.example.com --repo example.com/ai-operator# 创建 API 与 Controllerkubebuilder create api --group ai --version v1 --kind AIJob --resource=true --controller=true
text14 行
.├── api/v1/│   ├── aijob_types.go        # CRD 类型定义│   └── groupversion_info.go  # 组版本信息├── controllers/│   ├── aijob_controller.go   # 控制器循环逻辑│   └── suite_test.go         # 测试套件├── config/│   ├── crd/                  # 生成的 CRD 清单│   ├── manager/              # Operator 部署清单│   └── webhook/              # Webhook 配置├── Dockerfile                # 镜像构建├── Makefile                  # make 命令入口└── go.mod

Reconcile协调循环

如果说 Operator 是大厨,那么 Reconcile 循环就是大厨的“巡场节奏”——每完成一轮观察、对比、调整,就回到起点再来一轮,形成永不停歇的闭环。

Reconcile 函数标准签名:

这种“永不疲倦的巡场”正是声明式系统的魅力——用户只需声明一次期望,系统负责永远守护。

result,err=Reconcile(ctx,req)⇒调谐直到lim⁡t→∞(现实−期望)=0\displaystyle result, err = \text{Reconcile}(ctx, req) \Rightarrow \text{调谐直到} \lim_{t \to \infty} (\text{现实} - \text{期望}) = 0
  1. Get 获取动作通过请求中的命名空间和名称获取 CR 实例,像大厨看菜单确认客人点了什么
    r.Get(ctx,req.NamespacedName)⇒期望状态r.Get(ctx, req.NamespacedName) \Rightarrow \text{期望状态}
  2. List 现实观察动作列出关联的子资源,掌握当前实际状况
    r.List(ctx,PodList)⇒现实状态r.List(ctx, \text{PodList}) \Rightarrow \text{现实状态}
  3. 调谐计算动作比较期望与现实的差异,执行增删改操作
    Δ=desired_replicas−current_replicas⇒创建 Pod\Delta = \text{desired\_replicas} - \text{current\_replicas} \Rightarrow \text{创建 Pod}
  4. 返回值决定节奏返回 RequeueAfter 表示周期性地重新入队,持续保持收敛
    ctrl.Result{RequeueAfter:30s}⇒循环继续\text{ctrl.Result}\{\text{RequeueAfter}: 30s\} \Rightarrow \text{循环继续}
go19 行
func (r *AIJobReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {    // 1. 获取当前 AIJob 实例    var job aiv1.AIJob    if err := r.Get(ctx, req.NamespacedName, &job); err != nil {        return ctrl.Result{}, client.IgnoreNotFound(err)    }    // 2. 获取现实状态(现有 Pod 数量)    existingPods := &corev1.PodList{}    r.List(ctx, existingPods, client.MatchingLabels(map[string]string{"job": job.Name}))    // 3. 计算差异并调整    if len(existingPods.Items) < int(*job.Spec.Replicas) {        // 创建缺失的 Pod    }    // 4. 更新状态    job.Status.ReadyReplicas = len(existingPods.Items)    r.Status().Update(ctx, &job)    // 5. 返回重新入队    return ctrl.Result{RequeueAfter: 30 * time.Second}, nil}

Webhook准入校验

客人点了一道“不存在的菜”怎么办?Webhook 就是餐厅门口的“专业门卫”——在订单(请求)正式进入厨房(API Server 持久化)之前,拦截检查。Kubebuilder 中常见的 Webhook 有两类:Mutating Webhook(默认值填充)和 Validating Webhook(合法性校验)。

Go 中的实现方式:

Webhook 的工作流程:

门卫的存在让餐厅免于“客人点了满满一桌不存在的菜”的混乱。同理,Webhook 让 Operator 在请求源头就拦截大部分错误配置,减轻 Reconcile 循环的负担。

API 请求→Mutating 填默认值→Validating 校验规则→持久化到 etcd\text{API 请求} \rightarrow \text{Mutating 填默认值} \rightarrow \text{Validating 校验规则} \rightarrow \text{持久化到 etcd}
  1. Mutating 修改动作在对象持久化前自动填充未设置的字段,就像门卫友善地提醒“您点的菜默认配米饭”
    Default():replicas=1 if nil\text{Default()}: \text{replicas} = \text{1} \text{ if } \text{nil}
  2. Validating 校验动作按业务规则检查请求合法性,非法请求直接拒绝
    ValidateCreate():replicas>100⇒拒绝请求\text{ValidateCreate()}: \text{replicas} > 100 \Rightarrow \text{拒绝请求}
  3. 注解路由动作通过 +kubebuilder:webhook 注解声明 Webhook 的路径与触发条件
    路径⇒mutate/validate⇒规则匹配⇒拦截调用\text{路径} \Rightarrow \text{mutate/validate} \Rightarrow \text{规则匹配} \Rightarrow \text{拦截调用}
go14 行
// +kubebuilder:webhook:path=/mutate-ai-example-com-v1-aijob,mutating=true,failurePolicy=fail,groups=ai.example.com,resources=aijobs,verbs=create;update,versions=v1,name=maijob.ai.example.com func (r *AIJob) Default() {    if r.Spec.Replicas == nil {        r.Spec.Replicas = pointer.Int32Ptr(1) // 默认单副本    }} func (r *AIJob) ValidateCreate() (admission.Warnings, error) {    if *r.Spec.Replicas > 100 {        return nil, fmt.Errorf("replicas 不能超过 100")    }    return nil, nil}

AI 应用场景

AI训练任务生命周期管理

阶段:模型训练与部署运维

解决的问题:传统方式中,数据科学家需要手工创建 GPU Pod、编写训练脚本、配置 tensorboard 服务、结束后手动清理资源、保存 Checkpoint 到对象存储——每个环节都要操作一堆 YAML,极易出错且无法复用。通过自定义 AIJob CRD,用户只需提交一个训练任务描述,Operator 自动完成资源申请、环境准备、分布式调度、日志收集、失败重试、产物归档。

具体案例:某 AI 平台团队用 Kubebuilder 开发了 AIJob Operator。数据科学家提交一个 AIJob CR——声明模型代码仓库地址、GPU 数量、数据集版本。Operator 自动创建对应的 Training Pod、挂载数据卷、启动 TensorBoard、配置日志采集 Sidecar;训练结束后自动保存 Checkpoint、回收资源,并在 status 中输出模型评估指标。

大模型推理服务自动扩缩容

阶段:模型推理服务部署与弹性伸缩

解决的问题:大模型推理服务需要根据请求量自动扩缩容,且不同模型版本需要独立的 Serving 实例。手写 HPA + Deployment 难以表达“模型版本灰度、请求量感知扩缩、GPU 显存监控、版本回滚”等复杂策略。自定义 InferenceService CRD 让用户声明式地描述推理服务拓扑,Operator 负责落地执行。

具体案例:某企业用 Kubebuilder 开发了 InferenceService Operator,支持“按 Token 吞吐量”扩缩容(比 CPU 指标更精确)、多版本金丝雀发布、GPU 显存水位检测自动扩容、异常版本自动回滚。算法工程师只需提交一个 CR,就能获得一个生产级的推理服务。

AI流水线的定时调度与依赖管理

阶段:周期性的数据处理与模型重训

解决的问题:特征工程、模型重训、评估报表等任务有严格的前后依赖关系(如“数据清洗完成才能开始训练”),原生 CronJob 无法表达“任务 A 成功后触发任务 B”的 DAG 逻辑。自定义 PipelineRun CRD 将流水线描述为任务图,Operator 按依赖顺序依次执行。

具体案例:某推荐系统团队用 Operator 实现了 PipelineRun 调度器:每个 PipelineRun 定义“清洗→训练→评估→上线”四阶段 DAG,Operator 监听上游任务状态,满足条件才启动下游任务;失败自动重试,并在 status 中展示整体流水线进度与每阶段日志入口。

Python 演示

python81 行
import timeimport randomfrom dataclasses import dataclass, field  @dataclassclass AIJob:    name: str    desired_replicas: int    actual_replicas: int = 0    phase: str = "Pending"  class MiniOperator:    """模拟 Kubebuilder 生成的 Operator 控制器"""     def __init__(self, job: AIJob):        self.job = job        self.observed_generation = 0        self.reconcile_count = 0     def observe(self) -> dict:        """步骤1: 观察现实状态"""        return {"actual": self.job.actual_replicas, "desired": self.job.desired_replicas}     def compare(self, state: dict) -> int:        """步骤2: 计算期望与现实的差距"""        return state["desired"] - state["actual"]     def actuate(self, diff: int) -> None:        """步骤3: 根据差距执行调整"""        if diff > 0:            created = min(diff, random.randint(1, 3))            self.job.actual_replicas += created            self.job.phase = "ScalingUp"            print(f"  [动作] 创建 {created} 个 Pod")        elif diff < 0:            removed = min(abs(diff), random.randint(1, 2))            self.job.actual_replicas -= removed            self.job.phase = "ScalingDown"            print(f"  [动作] 删除 {removed} 个 Pod")        else:            self.job.phase = "Stable"     def update_status(self) -> None:        """步骤4: 回写状态"""        self.observed_generation += 1        print(f"  [状态] generation={self.observed_generation} phase={self.job.phase}")     def reconcile(self) -> bool:        """执行一轮完整的协调循环"""        self.reconcile_count += 1        print(f"=== Reconcile #{self.reconcile_count} ===")        state = self.observe()        print(f"  观察: desired={state['desired']} actual={state['actual']}")        diff = self.compare(state)        if diff == 0:            self.update_status()            return True        self.actuate(diff)        self.update_status()        return False  def main():    print(">>> 创建 AIJob: 期望 5 个训练副本")    job = AIJob(name="resnet50-train", desired_replicas=5)    op = MiniOperator(job)     for _ in range(10):        done = op.reconcile()        if done:            print(">>> 已收敛,现实与期望一致!")            break        time.sleep(0.5)     print(f">>> 最终状态: 实际副本数 = {job.actual_replicas}, 阶段 = {job.phase}")  if __name__ == "__main__":    main()
目的:用 Python 模拟 Operator 的 Reconcile 主循环,演示“观察→对比→调整→收敛”的协调逻辑,与 Kubebuilder 生成的 Go 控制器行为一一对应。
  1. @dataclass class AIJob定义自定义资源的数据模型,对应 Go 中的 AIJobSpec/Status 结构体
  2. def observe()收集现实状态,对应 r.List() 获取现有 Pod 数量
  3. def compare()计算期望与现实的差距 Δ,对应 Reconcile 中的差异计算
  4. def actuate(diff)根据差距创建/删除 Pod,对应调谐动作
  5. actual_replicas += created模拟 Pod 创建成功后的现实状态更新
  6. if diff == 0: return True收敛判断,对应 ctrl.Result{} 不需要立即重试
  7. job.phase = "Stable"状态更新,对应 r.Status().Update()

常见误区

误区定义了 CRD 之后,Kubernetes 就会自动帮我管理这些自定义资源——比如自动创建 Pod、自动扩缩容。CRD 本身不就能执行操作吗?

正解CRD 只是一张声明了字段格式的“空白菜单模板”,它只负责让 API Server 接受并存储这类对象,完全不包含任何业务逻辑。真正干活的 Operator 是另一套程序——它像大厨一样盯着菜单去做菜。没有 Operator 的 CRD 就像一个空壳食堂:菜单挂满墙,却没有厨师上灶。定义 CRD 只是有了“数据模型”,编写 Controller 才有“行为逻辑”。

为何常见:很多人把 CRD 和 Operator 混为一谈,觉得在 Kubernetes 里新增一个资源类型,平台“应该”会自动处理它——这混淆了“存储定义”与“执行逻辑”两个层次。

误区Reconcile 函数只在资源发生变化时才被调用,就像事件回调一样——一次请求一次响应。

正解Reconcile 是基于“期望状态”的持续协调循环,不是一次性事件处理。即使没有任何事件发生,控制器也会因为 RequeueAfter 定时器、周期性的 resync 或子资源的变化频繁被调用。它每次运行时都重新读全量状态、重新计算差异——就像一个每 30 秒巡场的大厨,即使没有新订单也会检查每道菜的温度。这种“冗余计算”正是声明式系统的致胜法宝:永远自我修复、自愈漂移。

为何常见:习惯了传统“事件回调”编程模型的人,容易把 Reconcile 理解为“每当 X 变化就触发 Y”,忽略了它“周期性地把现实拉回期望”的核心本质。

误区写 Operator 时只要能创建 Pod 就大功告成,`status` 字段可写可不写,反正不影响业务。

正解status 是 Operator 的“仪表盘反馈”,是用户了解自定义资源状态的关键通道,也是控制器做差异计算的依据。训练任务当前跑到哪个 epoch?有几个副本 ready?这些信息必须通过 status 暴露给用户和上层系统。更关键的是,写 status 需要调用 Status().Update() 而不是普通的 Update(),二者权限不同——普通更新无法修改 status 字段。忽视 status,相当于大厨做菜从不向客人反馈“菜做到哪一步了”。

为何常见:初学阶段容易把重心放在“创建 Pod”上,而忘了 status 是 Reconcile 循环中“下一步决策”的信息基础,也忘了 status 子资源的特殊权限模型。

误区Operator 的所有能力都应该在 Reconcile 函数里实现——校验、默认值、权限检查都放进去就行。

正解Reconcile 只是“调谐”逻辑,它假定请求的 CR 已经通过了合法性校验。默认值填充应该放在 Mutating Webhook 的 Default() 中,字段合法性校验应放在 Validating Webhook 的 ValidateCreate/ValidateUpdate 中。三类逻辑职责分离,如同餐厅的“门卫管拦人、厨师管做菜、经理管巡场”——各司其职。把所有逻辑堆进 Reconcile 会导致循环频繁触发、错误无法在入口拦截、代码耦合严重。

为何常见:对 Kubebuilder 脚手架生成的三个入口(Reconcile、Default、Validate*)不够了解,一股脑把逻辑写进最熟悉的 Reconcile 里。

面试题

Q1. CRD 在 Kubernetes 中的作用是什么?

单选题 · easy

  • A.直接管理 Pod 的生命周期
  • B.定义新的自定义资源类型← 正确答案
  • C.替代 ConfigMap 存储配置
  • D.自动负载均衡集群流量

答案:B。CRD 是 CustomResourceDefinition 的缩写,作用相当于“空白菜单模板”,它向 API Server 注册一种新的资源类型(如 AIJob),但本身不执行任何管理操作。Pod 生命周期由 Controller 管理,配置存储是 ConfigMap 的职责,负载均衡是 Service/Ingress 的职责。

Q2. Operator 模式的核心价值是什么?

单选题 · easy

  • A.替代 Docker 构建容器镜像
  • B.将领域运维知识固化为自动化控制器← 正确答案
  • C.加速 Kubernetes 集群的安装
  • D.为 Pod 提供网络加密通道

答案:B。Operator 就像把大厨的做菜经验变成自动化菜谱执行器,它将某个领域(AI 训练、数据库)的运维知识编码到控制器中,持续把现实状态调谐到期望状态。它不涉及镜像构建、集群安装或网络加密,那些分别属于 Docker、kubeadm 和 Cilium 等功能。

Q3. Reconcile 循环中,计算出的差异值 Δ 代表什么?

单选题 · mid

  • A.期望副本数与实际副本数之差← 正确答案
  • B.集群节点的总内存大小
  • C.API Server 的响应延迟
  • D.容器镜像的层数

答案:A。Δ = desired - actual,如同大厨对比“菜单上写 5 道菜”与“实际做好 3 道菜”的差距。这个差值驱动调谐动作:Δ > 0 则创建资源,Δ < 0 则删除资源。其余选项均与协调循环的差异计算无关。

Q4. 在 Kubebuilder 生成的代码中,修改 CRD 字段后需要执行哪个命令重新生成清单?

单选题 · mid

  • A.make build
  • B.make manifests← 正确答案
  • C.make run
  • D.make test

答案:B。make manifests 会根据 Go 结构体注释自动生成 CRD YAML 清单和 RBAC 配置,如同厨师学校根据菜谱自动更新教学大纲。make build 编译二进制,make run 本地运行控制器,make test 执行测试。

Q5. Mutating Webhook 的主要职责是什么?

单选题 · mid

  • A.拦截请求并修改对象的默认值← 正确答案
  • B.验证对象是否符合业务规则
  • C.定期删除过期数据
  • D.监控集群节点的健康状态

答案:A。Mutating Webhook 如同门卫在客人下单时自动“补充默认规则”——默认配米饭、默认辣度微辣。它在对象持久化之前修改字段(如设置默认副本数),而 Validating Webhook 才负责校验合法性。删除过期数据和节点监控都不属于 Webhook 的职责。

Q6. 关于 status 子资源的正确说法有哪些?

多选题 · mid

  • A.可通过普通 Update 直接修改
  • B.需通过 Status().Update() 更新← 正确答案
  • C.用于记录系统对 CR 的实际反馈← 正确答案
  • D.与 spec 拥有完全相同的权限

答案:BC。status 是系统的“仪表盘”,记录实际状态(如当前副本数、训练阶段),更新时必须调用 Status().Update(),因为 status 子资源绑定了更严格的 RBAC 权限。普通 Update() 无法修改 status 字段,选项 D 错误,选项 A 与 B 互斥且 B 正确。

Q7. Reconcile 函数返回 ctrl.Result{RequeueAfter: 30 * time.Second} 的含义是什么?

单选题 · hard

  • A.立即停止控制器并退出程序
  • B.告知 API Server 取消当前请求
  • C.30 秒后将该 key 重新加入队列← 正确答案
  • D.将控制器的日志级别降为 Warning

答案:C。这相当于大厨定好“每 30 秒巡场一次”的闹钟。返回 RequeueAfter 表示本次调谐不需要立即重试,但需要在 30 秒后再次入队进行周期性检查。这样做是为了处理周期性状态变化(如证书轮换、定时检查),而不是停止、取消或降级日志。

Q8. Kubebuilder 中使用 +kubebuilder:webhook 注解声明 Webhook 的目的是什么?

单选题 · hard

  • A.声明 Webhook 的路径、资源和触发条件← 正确答案
  • B.给 Webhook 添加日志输出功能
  • C.指定 Webhook 的镜像版本
  • D.为 Webhook 创建 ServiceMonitor

答案:A。注解是 Kubebuilder 的“声明式配置”,像餐厅门口的“门卫岗位说明”——写明在哪个路径值班(/mutate-ai-example-com-v1-aijob)、拦哪些资源(aijobs)、什么动作触发(create;update)。它让 make manifests 自动生成 Deployment 中所需的 Webhook 配置,无需手写 YAML。

Q9. CRD 中 storage: true 表示什么?

单选题 · easy

  • A.该版本作为持久化存储的唯一版本← 正确答案
  • B.该版本仅用于临时缓存
  • C.该版本必须删除所有数据
  • D.该版本优先用于网络传输

答案:A。多版本 CRD 中,storage: true 标记的版本用于在 etcd 中持久化对象数据,如同餐厅纪念册只收藏经典版本的招牌菜。其他版本可能被 API 服务(served: true)但数据统一以 storage 版本落盘。

Q10. Operator 的 Reconcile 循环中包含哪些典型步骤?

多选题 · hard

  • A.获取期望状态的 CR 实例← 正确答案
  • B.列出相关的子资源观察现实状态← 正确答案
  • C.根据差异执行资源的增删改操作← 正确答案
  • D.修改 CRD 的 Schema 字段定义

答案:ABC。Reconcile 的四个基本动作是:Get(获取 CR)、List(观察子资源)、计算差异并执行操作、更新状态并返回结果。它不会修改 CRD 的 Schema——Schema 是资源类型的定义(菜单模板),实例才是运行中的数据(具体订单),控制器只操作实例不修改模板。