想象你住在一个云端智慧小区,物业中心备有一整套标准登记表:住户登记表、公寓入住表、访客通行证。这些表对应 Kubernetes 里内建的资源类型,比如 Pod、Deployment。某天,小区计划新增一个「AI 模型游乐园」,标准登记表里根本没有这一项,于是物业中心设计了一张全新的「宠物乐园登记表」——这就是 CRD(自定义资源定义)。但光有登记表还不够,游乐园建好后还需要一位不知疲倦的「专属管家」来检查设施、清理场地、调整设备,让现实状态始终贴合表格上写的「理想状态」。这位管家就是 Operator。本文会用这个「小区物业」的比喻,带你从零看懂 CRD 与 Operator 是什么、如何工作,以及它们为什么能让 AI 模型服务真正实现自动化运维。

岗位关联

对 AI 从业者来说,掌握 CRD 与 Operator,意味着你能把模型训练、推理服务、自动伸缩这些领域知识写成 Kubernetes 原生自动化能力,成为云原生 AI 基础设施的「设计师」而非单纯的使用者。

目录
  1. 可视化演示
  2. CRD 概念入门
  3. API 定义规范
  4. 协调循环原理
  5. Operator 设计模式
  6. controller-runtime 实践
  7. 高可用与状态管理
  8. AI 模型服务实战
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

展示Kubernetes自定义资源定义CRD与Operator模式:API扩展机制、控制循环Reconcile、Leader选举高可用及AI模型服务自动化实践。切换模式查看不同环节。

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

CRD定义与API扩展 CRD声明自定义资源类型,扩展Kubernetes API Server Custom Resource通过kubectl管理,与原生资源体验一致 CRD → API → CR (instance) CRD将领域模型注入K8s生态

CRD 概念入门

物业中心的文件柜里,已经有「住户登记表」「公寓入住表」这些标准表。忽然有一天,小区要开设「AI 模型游乐园」,但现有表格里没有任何一类能描述「游乐园想养几只模型、需要多少显卡、对外服务端口是多少」。于是物业中心提交了一份崭新的「宠物乐园登记表」给总管理处(Kubernetes API Server),申请把这个新表纳入官方表格体系。这张新表,就是你向 Kubernetes 申请的自定义资源定义 CRD。

在 Kubernetes 集群中,Pod、Deployment、Service 是内建资源;CRD 是让你自己发明新资源类型的方法。开发者提交一份 YAML 配置,声明「我想要一个模型服务,两个副本,模型名 bert」,这份配置被称为自定义资源对象。Kubernetes 并不会真的帮你拉起模型,它只是把你的「心愿单」存下来——真正的执行者,是后续会出现的 Operator。

自定义资源本质上就是「类型 + 声明」的组合:类型告诉系统这是什么,声明告诉系统你希望它最终变成什么样。

回到小区比喻:你递给物业的「宠物乐园登记表」,只是让系统知道世上存在这种表、也知道你想要的设施清单。可如果没有管家来按表施工和照看,这张表就永远只是一纸空文。

CustomResource=(Kind,Group,Version,Spec)\displaystyle \text{CustomResource} = (\text{Kind}, \text{Group}, \text{Version}, \text{Spec})
这句话的含义是:一个自定义资源对象由「种类 + 组 + 版本 + 期望规格」四个部分唯一确定,就像一份登记表由「表名 + 归属部门 + 表单版本 + 填写内容」组成。
  1. Kind(种类)定义这份登记表的名字,例如 ModelService。
    Kind=ModelService\displaystyle \text{Kind} = \text{ModelService}
  2. Group(组)给这一类资源分组,避免不同领域的资源重名,例如 ai.example.com。
    Group=ai.example.com\displaystyle \text{Group} = \text{ai.example.com}
  3. Version(版本)表示登记表的版本号,例如 v1,方便未来演进字段。
    Version=v1\displaystyle \text{Version} = v1
  4. Spec(期望规格)用户填写的心愿清单,描述模型的副本数、镜像、端口等。
    Spec={replicas,model,port}\displaystyle \text{Spec} = \{ \text{replicas}, \text{model}, \text{port} \}

API 定义规范

拿到新表之前,物业中心需要先规定表格的「版式」:哪些格子必须填、填数字还是填文本、可不可以留空。在 Kubernetes 中,这份「版式」就是 CRD 的 Schema,它用 OpenAPI 描述自定义资源的字段结构。

定义 Schema 时,最核心的是 spec 字段的结构。比如 replicas 的类型是整数,范围是 1 到 100;model 是字符串且不能为空;port 是 1 到 65535 的整数。这样当用户提交 YAML 时,API Server 可以直接校验格式,不合法就拒绝存储。就像物业管理员一眼看出「登记表里年龄填了 -5」,马上打回。

除了校验,Schema 还能设置默认值。如果用户没写 replicas,系统自动填入 1;如果没写 strategy,默认使用 RollingUpdate。这些规则让用户写配置时更轻松,也让资源行为更可控。

表格版式定好了,剩下的问题就是:谁来照着这份版式,把小区的宠物乐园真正建起来并维护好?这个答案,正是后面的「协调循环」。

Schema={properties,required,default}\displaystyle \text{Schema} = \{ \text{properties}, \text{required}, \text{default} \}
Schema 是资源的「字段说明书」:properties 列出所有可填字段,required 标注必填项,default 为未填写的字段补上默认值。
  1. properties(字段集合)列出哪些格子可以填以及各自类型。
    properties={replicas:integer,model:string}\displaystyle \text{properties} = \{ \text{replicas}: \text{integer}, \text{model}: \text{string} \}
  2. required(必填项)规定哪些字段不能省略,例如 model。
    required=[model]\displaystyle \text{required} = [\text{model}]
  3. default(默认值)用户没填时系统自动补上的值。
    default={replicas:1}\displaystyle \text{default} = \{ \text{replicas}: 1 \}

协调循环原理

管家怎么知道该干活呢?他不会等业主来吆喝,而是每隔一会儿就在小区里转一圈,对照「登记表上的理想样子」和「游乐园的当前样子」:要是垃圾桶满了就清空,要是设施坏了就报修,要是宠物少了就补领。这种「看两眼、改一改、再看两眼」的循环,在 Kubernetes 里叫协调循环。

在 Operator 中,核心逻辑被封装进一个函数:Reconcile。当自定义资源被创建、更新、删除,或底层资源状态发生变化时,事件会触发这个函数。它读取资源当前的 Spec 和 Status,算出期望与现实的差距,然后执行创建 Pod、更新 Deployment、滚动升级等操作,操作完成后再次观察。

如果把协调循环写成直觉公式,就是:期望状态减去实际状态等于误差,当误差不为零时,控制器就该行动了。

管家不会因为打扫过一次就永远收工,只要小区状态发生变化,他都会再次出现在宠物乐园里检查。这种永不满足的「纠偏」机制,正是 Operator 能持续保证系统处于期望状态的原因。

Δ=Desired−Actual\displaystyle \Delta = \text{Desired} - \text{Actual}
这里的 Δ 是「现实与梦想的差距」:差距为零岁月静好,差距非零则触发运维动作,直到差距消失。
  1. Desired(期望状态)来自 CRD 对象的 spec,即用户声明的心愿。
    Desired=Spec\displaystyle \text{Desired} = \text{Spec}
  2. Actual(实际状态)从集群中观察到的事实,比如当前 Pod 数量、镜像版本。
    Actual=Observed State\displaystyle \text{Actual} = \text{Observed State}
  3. Δ(差距)期望与实际的差,决定是否需要动作。
    Δ=Desired−Actual\displaystyle \Delta = \text{Desired} - \text{Actual}
  4. 动作策略Δ 不为 0 时,调整资源让 Δ 趋近于 0。
    Reconcile→Action\displaystyle \text{Reconcile} \to \text{Action}

Operator 设计模式

如果说 CRD 是登记表,那么 Operator 就是负责照单维护的专属管家。它的设计模式很简单:用 CRD 定义资源的「期望结构」,再用一个控制器监听这类资源的生命周期,按你写好的运维逻辑自动执行。传统运维靠人盯着监控、手动扩容、手动回滚;Operator 把人的经验固化成代码,让机器自己盯着。

比如一个 AI 模型的线上服务,过去需要运维同学半夜盯告警、手动拉起新 Pod。有了 Operator,Controller 会定期检查模型服务副本数、GPU 利用率、模型版本是否与 Spec 一致。不一致就自动调整,完全不需要人肉介入。

所以,Operator 不是一个神秘的黑盒,它是「控制器 + 自定义资源 + 领域知识」的组合,把一个垂直领域的运维自动化变成现实。

有了这位专属管家,小区管理者不再需要为每一件小事操心。但要让管家在真实小区里可靠上岗,我们还需要一套标准工具来「雇佣」他——这就是 controller-runtime 框架。

Operator=Controller+CRD+Domain Knowledge\displaystyle \text{Operator} = \text{Controller} + \text{CRD} + \text{Domain Knowledge}
你可以这样理解:Controller 是管家的手脚,CRD 是管家的岗位说明书,Domain Knowledge 是管家心中那套「怎么养好一只 AI 模型」的行业经验。
  1. Controller(控制器)持续 watch 自定义资源并触发 Reconcile 的执行框架。
    Controller→Watch+Reconcile\displaystyle \text{Controller} \to \text{Watch} + \text{Reconcile}
  2. CRD(自定义资源)为管家定义工作的「对象清单」。
    CRD=Kind+Schema\displaystyle \text{CRD} = \text{Kind} + \text{Schema}
  3. Domain Knowledge(领域知识)把「如何扩容」「如何回滚」等判断规则写入代码。
    Rule=if  Δ>0  then  Action\displaystyle \text{Rule} = \text{if} \; \Delta > 0 \; \text{then} \; \text{Action}

controller-runtime 实践

自己从零搭建一个 Kubernetes 控制器,首先要写 API 客户端、事件监听、缓存、重试队列,工作量巨大。于是社区提供了 controller-runtime 库,相当于给所有 Operator 管家提供了一套标准培训体系和工具箱。你只需要关心 Reconcile 函数里写什么业务逻辑,其他与 K8s 交互的复杂度由框架接管。

在这个框架里,Manager 是总调度中心:它负责启动所有控制器、维护缓存、提供客户端。Builder 则像招聘流程:指定 watch 哪种资源,再把事件交给哪个 Reconcile 方法。开发者通常用 ctrl.NewControllerManagedBy(mgr) 在几行代码内完成「监听 ModelService 资源,并调用 Reconcile 处理」的装配。

Reconcile 函数本身是一个纯逻辑函数,它接收一个资源名字(NamespacedName),返回处理结果。框架负责把事件变成调用,把重试和排队从业务逻辑中剥离出去。

有了统一工具箱,Operator 的开发效率大幅提升。不过,当很多小区业主同时依赖这位管家时,还要解决「多个管家不能重复打扫」的问题。

Reconcile:NamespacedName→Result\displaystyle \text{Reconcile}: \text{NamespacedName} \to \text{Result}
简单说,框架把「何时触发、触发谁」的机制都做好了,你只需要写「被触发后该干什么」。
  1. NamespacedName(资源定位)标识一个资源所在的命名空间和名字。
    NamespacedName=(namespace,name)\displaystyle \text{NamespacedName} = (\text{namespace}, \text{name})
  2. Reconcile 方法根据名字读取资源并执行协调逻辑。
    Reconcile(req)=Result\displaystyle \text{Reconcile}(\text{req}) = \text{Result}
  3. Result(返回结果)告诉框架本次是否成功、何时重试。
    Result={Requeue:bool}\displaystyle \text{Result} = \{ \text{Requeue}: \text{bool} \}

高可用与状态管理

如果把 Operator 部署多份,就能避免单点故障。但如果两个管家同时发现垃圾桶满了,双双伸手去清,反而可能互相干扰。Kubernetes 给出的方案叫 Leader Election(领导者选举):所有副本中只选出一个「值班管家」,其余作为候补,只有在 Leader 挂掉时才顶上。

controller-runtime 内置了 Leader Election 机制。每个 Operator 副本启动时会争夺一个 lease 锁,获得锁的副本成为 Leader,真正执行 Reconcile;其他副本保持待命。这就像小区里虽然雇了三个管家,但只有戴着值班牌的那位可以动工具,其他人只观察、不干预。

另一个关键机制是 Status 子资源。用户定义的 spec 是「心愿」,控制器把实际运行情况写进 status,比如当前副本数、最近一次成功更新时间、可用的模型版本。Kubernetes 会保护 status 字段,普通用户不能随意篡改,只有控制器有权限写入,确保状态信息来源可信。Leader 数量 N 与配额 Q 的关系:

多个副本安全值班,状态又能被可信记录后,Operator 终于可以放心上岗。最后,我们来看看它是如何被用在 AI 模型服务这种真实的高价值场景中的。

Q=⌊N2⌋+1\displaystyle Q = \left\lfloor \frac{N}{2} \right\rfloor + 1
领导者选举要求获得超过半数的票才能当选。N 个副本中,候选者至少需要 Q 票才能成为唯一 Leader,避免脑裂。
  1. N(副本总数)参与选举的 Operator 实例数量。
    N=replicas\displaystyle N = \text{replicas}
  2. Q(法定票数)成为 Leader 所需的最小票数。
    Q=⌊N/2⌋+1\displaystyle Q = \lfloor N / 2 \rfloor + 1
  3. 选举条件只有得票数超过半数,才进入值班状态。
    Leader={x∣x∈Candidates,x≥Q}\displaystyle \text{Leader} = \{ x \mid x \in \text{Candidates}, x \geq Q \}

AI 模型服务实战

在 AI 平台中,模型从训练到上线、再到版本更新和回滚,链路非常长。传统方式是平台工程师写一堆运维脚本,再配一个值班机器人;但这种方式难以应对复杂状态变化。用 CRD 和 Operator,我们可以为「模型服务」量身定制一套自动化的生命周期管理系统。

比如定义一个 ModelService 自定义资源:用户提交 YAML,声明模型名、需要的 GPU 数量、期望副本数和版本策略。ModelService Operator 收到后,会自动创建底层 Deployment、Service、HorizontalPodAutoscaler,并把推理服务的实时状态写回 status。当模型流量突增时,Operator 还会根据等待队列长度自动扩缩容。

扩缩容可以抽象为一道简单计算题:假设当前请求负载为 L,单副本能承受的阈值为 T,那么需要的副本数 R 至少是 L/T 向上取整,并且不能小于 1。

回到「AI 模型游乐园」的比喻:ModelService CRD 是那张「游乐园经营申请书」,而 ModelService Operator 就是那个懂模型、懂 GPU、懂扩容缩容的超级管家。从今往后,你只需要在申请书上写清楚「我要多大的游乐园」,剩下的脏活累活,管家全部搞定。

R=max⁡(1,⌈LT⌉)\displaystyle R = \max\left(1, \left\lceil \frac{L}{T} \right\rceil\right)
当每秒请求数 L 超出单副本能力 T 时,系统按比例增加副本数;负载下降时再缩减,始终让资源用量贴合真实需求。
  1. L(当前负载)观测到的每秒请求数或排队任务数。
    L=current load\displaystyle L = \text{current load}
  2. T(单副本阈值)每个副本能承载的最大负载上限。
    T=threshold per replica\displaystyle T = \text{threshold per replica}
  3. R(目标副本数)需要的副本数量。
    R=⌈L/T⌉\displaystyle R = \lceil L / T \rceil

AI 应用场景

AI 模型服务的全自动发布与扩容

阶段:模型部署与运维

解决的问题:传统方式需要运维人员盯着监控,手动创建 Deployment、Service,流量突增时手动扩容,非常容易出错。通过 ModelService 自定义资源和 Operator,平台可以把「部署、扩容、回滚」固化成代码,自动完成。

具体案例:某算法团队上线一个 BERT 问答服务。他们在 YAML 里声明 replicas: 2、model: bert-base,提交后 Operator 自动创建底层资源;当压测流量达到单副本阈值的 80% 时,Operator 自动扩容到 5 个副本,并在流量回落后缩容。

模型版本灰度发布与自动回滚

阶段:模型版本管理

解决的问题:新版本模型可能效果变差或推理延迟飙升,人工回滚耗时且容易遗漏。Operator 可以监控新版 Pod 的启动成功率与延迟指标,一旦低于阈值,自动回滚到上一个稳定版本。

具体案例:某推荐系统发布 v2 模型,Operator 按 10% 流量灰度验证,发现错误率超过 5% 后自动把流量切回 v1,同时将 ModelService 的 status 标记为 RolledBack,方便研发排查。

多集群统一模型调度

阶段:多云与多集群模型分发

解决的问题:大公司跨地域部署多个 K8s 集群,每个集群的模型版本和资源状况难以统一。通过 CRD 定义跨集群的 ModelService,Operator 可以按集群负载自动分发模型。

具体案例:某语音识别团队使用 CustomResource 描述「模型需要华东区 4 张 A100、华南区 2 张 A100」,Operator 自动在多个集群间协调资源,保证服务就近接入。

Python 演示

python45 行
class ModelServiceOperator:    def __init__(self, model="bert", replicas=1):        self.model = model        self.replica_count = replicas        self.generation_count = 0     def fetch_actual(self):        return {            "replicas": self.replica_count,            "generation": self.generation_count        }     def apply_change(self, target_replicas):        self.replica_count = target_replicas        self.generation_count += 1     def reconcile(self, spec):        desired = spec.get("replicas", 1)        actual = self.fetch_actual()        if actual["replicas"] == desired:            return ("no-op", actual)        old = actual["replicas"]        self.apply_change(desired)        new_state = self.fetch_actual()        return ("scaled", {            "from": old,            "to": new_state["replicas"],            "generation": new_state["generation"]        })  def main():    operator = ModelServiceOperator(model="bert-base", replicas=2)    specs = [        {"name": "bert-qa", "replicas": 3},        {"name": "gpt-lite", "replicas": 1},        {"name": "bert-qa", "replicas": 3},    ]    for spec in specs:        action, detail = operator.reconcile(spec)        print("%s %s -> %s" % (spec["name"], action, detail))  if __name__ == "__main__":    main()
目的:用一段极简 Python 代码演示 Operator 的 Reconcile 核心逻辑:对比期望副本数与当前副本数,有差异就执行变更并更新 generation,没有差异就返回 no-op。
  1. class ModelServiceOperator:对应一个自定义资源的专属控制器,就像宠物乐园的专属管家。
  2. def fetch_actual(self)读取当前实际状态,对应控制器从 K8s 集群查询真实资源。
  3. def reconcile(self, spec)核心协调函数,比较 spec 中的期望值与 observed 实际值。
  4. if actual["replicas"] == desired:差距为零时无需动作,直接返回 no-op。
  5. self.apply_change(desired)差距非零时执行扩缩容,并更新 generation 记录变更代数。
  6. print("%s %s -> %s" % ...)模拟观察者看到的一次次协调结果。

常见误区

误区很多初学者认为只要 apply 一个 CRD 文件,Kubernetes 就会自动为这个新资源创建 Pod、Service 并维护运行状态。

正解CRD 只是「新登记表」的注册,它让 APIServer 认识这种资源类型、能存储和校验 schema,但不会执行任何业务逻辑。真正对资源进行创建、删除、扩容、回滚的,是监听这个 CRD 的 Operator/Controller。没有控制器,CRD 只是一张空表格。

为何常见:因为 K8s 内置资源都有对应的 controller-manager 组件自动管理,初学者容易误以为任何 CRD 也有系统内置的控制器。

误区不少人把「定义 CRD」和「开发 Operator」混为一谈,认为写完 CRD YAML 就算完成了一个 Operator。

正解CRD 定义数据模型,Operator 定义行为逻辑。一个完整的 Operator 至少包含两大部分:CRD(声明资源的 API 结构)和 Controller(对资源变化做出反应的协调逻辑)。只有 CRD 没有 Controller,相当于只有岗位说明书却没有员工来执行。

为何常见:因为很多 CRD 示例 YAML 里同时包含 Deployment 部署文件,让人以为 CRD 这个文件本身很完整,实际上还需要额外部署 Controller 镜像。

误区有人以为 Reconcile 是「一次性的回调函数」,资源状态匹配后就再也不执行了。

正解Reconcile 是持续性的协调循环,除了资源创建、更新、删除事件外,控制器还会周期性 re-list 资源,即使没有任何变更也会触发一次协调,以确保集群现状没有被外力漂移。

为何常见:因为很多教程只展示「新建资源后触发一次 reconcile」的场景,容易让人忽略 K8s 控制器的最终一致性设计本质。

误区为了高可用,有人把所有 Operator 副本都配置为活跃状态,认为这样可以提升处理速度。

正解普通无状态服务可以多副本同时服务,但 Operator 控制器在同一时刻只能有一个 Leader 执行 Reconcile,否则多个副本同时修改同一资源会导致资源冲突和重复操作。其他副本必须通过 Leader Election 进入待命状态。

为何常见:因为从小型 Website 服务的「多副本分流」直觉出发,会自然认为控制器副本也是多多益善,忽略了并发写冲突问题。

误区初学者以为 spec 和 status 都是资源对象的一部分,用户可以随时通过 kubectl edit 修改 status。

正解Kubernetes 将 CRD 的 spec 和 status 做了区分,并可以通过 subresources.status 开启 status 子资源保护。开启后,普通客户端保存资源时不会修改 status,只有控制器才有权更新 status,从而保证状态信息的可信度。

为何常见:因为一个 YAML 文件里确实可以同时看到 spec 和 status 字段,名称相似,容易让人忽略它们在 API 权限上的隔离。

面试题

Q1. CRD 在 Kubernetes 中的全称是什么?

单选题 · easy

  • A.Custom Resource Definition← 正确答案
  • B.Custom Runtime Design
  • C.Container Resource Driver
  • D.Configurable Role Definition

答案:A。CRD 全称是 Custom Resource Definition,用于定义用户自定义资源类型。其他选项都是对缩写字母的合理猜测,但并非 Kubernetes 官方术语。记住它是「资源定义」而非「运行时设计」即可。

Q2. Operator 模式的核心思想是什么?

单选题 · mid

  • A.把运维经验固化成控制器代码← 正确答案
  • B.用定时脚本任务代替人工巡检
  • C.让运维人员手动编辑 YAML 配置
  • D.通过 Webhook 修改 Kubernetes 源码

答案:A。Operator 的核心是把某个垂直领域的运维经验写成代码,由控制器自动执行。定时脚本通常只做一次性任务,而 Operator 基于事件驱动和协调循环,能持续保证期望状态,所以 A 更准确。

Q3. CRD 定义中通常包含哪些部分?

多选题 · mid

  • A.API 组与版本定义← 正确答案
  • B.资源字段结构定义← 正确答案
  • C.Pod 调度策略配置
  • D.网络负载均衡配置

答案:AB。CRD 定义的是资源的 API 元信息和 schema,包括 group、version、kind、properties 等。Pod 调度策略与网络负载均衡是部署细节,不属于 CRD 本身的定义范围,而是由 Operator 根据这些定义去创建底层资源。

Q4. 当 Reconcile 函数返回 error 时,controller-runtime 会发生什么?

单选题 · hard

  • A.将请求重新入队并再次协调← 正确答案
  • B.立即删除当前自定义资源
  • C.停止整个控制器进程
  • D.把资源状态强制改为失败

答案:A。返回 error 表示本次协调没有成功,框架会把该资源重新加入队列,并按退避策略重试。删除资源、退出进程、强制修改 status 都不是默认行为。错误重试机制保证了系统在异常情况下依然具备自愈能力。

Q5. Leader Election 在 Operator 中的主要作用是什么?

单选题 · mid

  • A.确保同时只有一个活跃控制器工作← 正确答案
  • B.随机删除异常 Pod 以恢复集群
  • C.自动扩展 Operator 的副本数量
  • D.更新 CRD 的 schema 版本

答案:A。Leader Election 用于多副本控制器选主,只有 Leader 执行 Reconcile,其余副本待命。它不是删除 Pod 或扩缩容的机制,也不负责 CRD 版本升级。多副本下没有 Leader Election 会导致多个控制器写同一资源。

Q6. 下面哪些属于 ModelService Operator 的典型职责?

多选题 · hard

  • A.监听 ModelService 资源变化← 正确答案
  • B.创建底层 Deployment 与 Service← 正确答案
  • C.把运行状态写回 status 字段← 正确答案
  • D.直接修改用户提交的 YAML 文件

答案:ABC。Operator 会 watch 自定义资源、创建管理底层资源、并更新 status 反映实际状态。它不会修改用户来源的 CR 对象定义,spec 由用户声明、status 由控制器维护,两者职责分离。

Q7. controller-runtime 中负责启动并管理多个控制器的组件是?

单选题 · easy

  • A.Manager← 正确答案
  • B.Webhook
  • C.Informer
  • D.Scheduler

答案:A。Manager 是 controller-runtime 的顶层组件,负责初始化客户端、缓存、Leader Election 以及注册和启动控制器。Webhook 用于准入校验,Informer 负责事件监听,Scheduler 负责 Pod 调度,二者都不是管理控制器的组件。

Q8. Status 子资源的用途是什么?

单选题 · mid

  • A.保存控制器观测到的运行状态← 正确答案
  • B.存储用户输入的模型参数
  • C.定义资源的字段校验规则
  • D.配置容器镜像地址

答案:A。status 保存的是实际运行状态,比如副本数、版本、条件信息,由控制器写入。用户输入参数属于 spec,校验规则属于 schema,镜像地址也是 spec 的一部分。Status 与 Spec 分离是 Operator 设计的重要原则。

Q9. 创建 CRD 后,要让自定义资源真正生效还需要做什么?

单选题 · easy

  • A.部署对应的 Operator 控制器← 正确答案
  • B.重启 Kubernetes 所有节点
  • C.修改 kube-apiserver 源码
  • D.为每个 Node 手动执行 script

答案:A。CRD 只是注册资源类型,真正为资源提供业务能力的是 Operator。部署控制器后,它才会监听资源并执行创建、更新、删除等逻辑。重启节点和修改源码显然不是正确做法。

Q10. 关于事件与 Reconcile 的关系,哪些说法是正确的?

多选题 · extreme

  • A.watch 到资源事件后会把请求入队← 正确答案
  • B.Reconcile 函数不需要读取实际状态
  • C.所有待处理事件共享一个工作队列← 正确答案
  • D.状态变化后不需要重新触发协调

答案:AC。controller-runtime 通过 watch 监听资源事件,事件被放入共享工作队列,然后由 Reconcile 消费处理。Reconcile 必须读取实际状态才能计算差距。状态变化后也应该产生新事件并入队,从而继续协调,因此 D 错误。