想象你经营一家大型酒店。酒店不能只有前台、厨房和客房,还要有一套清晰的“后台班子”:有人负责接单办入住,有人负责保存所有房态记录,有人负责排班派活,有人负责检查房间是否达到标准。与此同时,每一层楼还得有领班,专门执行具体清扫和设备维护。如果所有角色都挤在同一个办公室,酒店早就乱成一锅粥。Kubernetes 的架构思路正是如此——它把一台台服务器分成“控制面”与“工作节点”两类角色。控制面像酒店的管理层,负责决策、调度和校验;工作节点像各个楼层的领班,负责真正运行容器、处理流量。整篇文章将用这座“酒店”作为贯穿始终的比喻,带你看懂 K8s 控制面与工作节点如何各司其职、默契配合。
理解 K8s 控制面与工作节点的分工,是定位线上故障、优化集群性能、设计高可用平台的必修基本功。
可视化演示
演示控制面组件交互、调度器过滤打分绑定流程,以及声明式API的控制循环协调机制,可切换三种模式观察Pod如何被调度运行。
本节配有交互动效(进入视口后自动加载,约 3KB)。
控制面组件交互 API Server是集群唯一入口,所有操作经它 etcd用Raft共识存储集群状态,Scheduler调度为Pod选节点 State = etcd(Raft) Controller Manager维持期望状态,kubelet执行。
集群总览
假设你经营一家五星酒店。如果所有人都挤在同一个办公室里,既要接电话,又要跑去每个房间打扫,很快前台就会陷入混乱。一家成熟的酒店一定会把“管理区”和“楼层区”分开:管理区负责接单、排班、盯服务标准,楼层区则负责真正铺床、送餐、清扫。Kubernetes 的架构思路和这家酒店完全一致。
K8s 把一台台服务器分成两类角色。控制面(Control Plane)节点相当于酒店的管理区,工作节点(Worker Node)相当于客房楼层。控制面通常由 4 个组件协作完成决策:API Server 负责接单,etcd 负责存档,Scheduler 负责排班,Controller Manager 负责质检。工作节点则运行 kubelet(楼层领班)、容器运行时(清扫工具)和 kube-proxy(礼宾接线)。控制面一般不放业务,专注协调;真正承载业务服务的 Pod 落在工作节点上。
从数学上看,一个 K8s 集群就是控制面集合与工作节点集合的并集。
把集群看作一个整体,理解这层结构后就会发现:控制面再怎么聪明,没有工作节点去执行就是纸上谈兵;工作节点再拼命,没有控制面的调度和校验也会各自为战。酒店的“管理区+楼层区”缺一不可,Kubernetes 的“控制面+工作节点”也正是这样形成合力的。
- 集群等号左边代表整个 K8s 集群,右边说明它由两部分拼接而成。
- 控制面集合包含 API Server、etcd、Scheduler、Controller Manager 的组件组,是集群的大脑。
- 并集符号表示两个区域通过网络连成一个整体,缺一不可。
- 工作节点集合包含 kubelet、容器运行时、kube-proxy 的机器,负责运行业务容器。
统一入口
在酒店里,客人不会直接冲进档案室或厨房,所有入住、换房、点餐都要从总台登记。总台是唯一的对外窗口,也是唯一有权限修改房态记录的地方。K8s 里的 API Server 就是这样一个总台。
不管你是敲 kubectl 命令,还是用 SDK 调用,所有操作最终都会变成 REST 请求打到 API Server。它是集群里唯一的“写入口”,其他组件都不许绕过它私自改状态。API Server 会先做身份认证和权限校验,再经过准入控制,最后把资源状态写入 etcd。它的 Watch 机制还会主动把变化推送给订阅方,让其他组件第一时间感知。
一次普通请求的流转链路可以写成:
正因为一切都要过总台,K8s 才能保证订单的流程、校验、留痕都统一。设想一下,如果每个管理员都能直接改档案室,酒店必然乱套;让 API Server 大权独揽,虽然多了一道排队,却换来了整个集群的秩序。
- 请求对象用户执行
kubectl apply或调用 SDK 时,生成一条包含资源期望状态的请求。 - 客户端工具kubectl 只是翻译官,它把命令格式化成 API Server 能理解的 HTTP 请求。
- API Server 网关集群唯一入口,负责认证、授权、准入控制,并转发写入。
- etcd 持久化API Server 通过 Raft 协议把状态写入分布式数据库,完成“存档”。
状态仓库
档案室管理着一本大簿子,记录每个房间住的是谁、几点退房、是否有维修订单。任何人想了解房态,要么查档案,要么等档案室主动喊一嗓子。etcd 就是这本大簿子。
etcd 是 K8s 的分布式键值数据库,保存所有资源对象,包括 Deployment、Pod、Service 等。它不只存“配置”,而是整个集群的“唯一真相源”。为了不让数据混乱,etcd 通过 Raft 共识算法在多个副本之间同步,只有过半数副本确认才能写入。控制器们不需要反复轮询检查,而是用 Watch 机制盯着感兴趣的键,一旦发生变化立刻收到通知。
Raft 算法的关键数字是“法定人数”:
Raft 的法定人数规则就像开“紧急会议”:3 个档案员只要有 2 个确认就能拍板,5 个只要有 3 个确认。单个档案员请假不影响酒店运转。备份与恢复同样重要,因为档案一旦丢失,整个酒店的房态就成了谜。
- 法定人数 q一次写入需要至少多少个节点确认,q 是多数派的阈值。
- 半数取整n 个节点中先取一半,向下取整。
- 加一让数量严格超过一半,保证不会出现“两个多数派”分裂。
- 多数派保证3 节点集群 q=2,5 节点集群 q=3,这就是 Raft 的容错上限。
调度控制
排班经理拿到入住单,会先看哪些房间空着、资源是否满足要求,再决定派给哪个楼层。质检主管则不会检查一次就下班,而是每天对照标准手册巡逻,发现差距就安排整改。Scheduler 和 Controller Manager 正是这两位关键角色。
Scheduler 负责为新 Pod 选择最合适的工作节点:先过滤掉资源不足或不满足限制的节点,再对剩余候选节点打分,选出最优解。Controller Manager 里有一组控制器,例如 ReplicaSet 控制器,它们维护着一个控制循环:观察当前副本数,与期望副本数比较,若差异不为零就去创建或删除 Pod。你只需要在 YAML 里声明“我要 3 个副本”,系统就会持续调谐到满足期望,这就是声明式模型。
控制循环的“灵魂”是一个差值公式:
控制循环的核心思路,就是“盯着差距、反复修正”。这个逻辑让 K8s 具备强大的自愈能力:Pod 挂了就重新拉起,副本多了就自动回收,完全不需要工程师登录服务器手工处理。
- 期望状态由用户在 YAML 中声明的目标,比如“运行 3 个副本”。
- 当前状态集群中实际观察到的数量,比如现在只有 1 个副本。
- 差值二者相减。大于 0 表示不足,小于 0 表示多余。
- 调谐目标不断调整直到 Δ=0,这是所有控制器的共同目标。
节点执行
酒店管理区做了再完美的排班计划,还是要靠楼层领班敲开房门、检查床单、启用物品。楼层领班是管理区与客房之间的最后一道交接人。在 K8s 中,这道交接人就是 kubelet。
kubelet 运行在每个工作节点上,负责从 API Server 接收 Pod 的期望规格,然后调用容器运行时创建或销毁容器,并持续汇报运行状态。由于它只负责本节点,控制平面不必亲自登录每台机器。节点上的 kube-proxy 则像礼宾接线员:维护网络规则,让来自外部的访问能够负载均衡地转发到正确的 Pod。Pod 是 K8s 上最小的部署单元,可以装一个或多个容器,共享网络 IP 和存储卷。
Pod 的结构可以概括为:
你可以把 Pod 理解成“一间双人房”:几位客人共享同一个水电地址,楼层领班只检查整间房的状态。这样的设计让容器的生命周期、健康检查、流量接入被框进同一个管理单元,K8s 才能整齐划一地指挥成千上万个容器。
- 调度单元K8s 不直接调度单个容器,而是把关系紧密的容器打包成 Pod。
- 共享网络一个 Pod 一个 IP,容器之间通过 localhost 互通,共用一个网络命名空间。
- 共享存储Pod 内容器可挂载同一个卷,数据交换不依赖网络。
- N 个容器通常一个主容器加若干边车容器,协作完成一个完整任务。
运维实践
酒店经营久了,你会发现总台高峰排队、档案室磁盘变慢、某个楼层领班失联。成熟酒店会配置多套总台、定期备份档案,并对每个楼层做心跳巡检。K8s 的运维实践也围绕这几点展开。
首先是高可用设计:控制面通常部署多个节点,etcd 也做多副本,避免单点故障;工作节点通过资源预留避免 Pod 与系统组件争抢资源。其次是调优:给 API Server 配置合理的 QPS 和审计级别,给 etcd 更换高性能磁盘并开启压缩与定期快照,给 Scheduler 调整抢占策略和过滤逻辑。故障排查时,可以先用 kubectl describe、kubectl get events 看事件,再沿着“API Server → etcd → Controller → kubelet”的链路逐层定位。
系统可用性可以用这个公式表达:
可用性公式告诉我们:想让系统更可靠,要么延长“好日子”,要么缩短“坏日子”。K8s 的高可用架构和监控告警,本质上都是为了把这个分数做到 99.99%。
- 可用性 A系统实际可用的时间占比,生产环境通常追求 99.9% 以上。
- 平均无故障时间 MTBF两次故障之间平均能撑多久,越长越好。
- 平均修复时间 MTTR从故障发生到恢复需要多久,越短越能减少损失。
- 比值关系MTTR 越小或 MTBF 越大,A 越接近 1,这就是高可用的底层逻辑。
AI 应用场景
GitOps 发布平台
阶段:部署 / 交付
解决的问题:传统做法是用 SSH 登录服务器手动改配置,操作零散、容易漂移;GitOps 把“期望状态”写进 Git,AI 平台自动监听并同步,实现可审计、可回滚的发布。
具体案例:某金融团队把数百个微服务的 Deployment YAML 都放进 Git 仓库,ArgoCD 持续比较 Git 中的期望状态与集群当前状态。工程师只需合并代码,API Server 就会自动接收新期望,Controller Manager 和 Scheduler 随之完成滚动更新。
弹性扩缩容
阶段:资源调度与弹性伸缩
解决的问题:人工预估流量既不及时也容易浪费;K8s 的 HPA 控制器持续采集 CPU 与请求量指标,根据公式计算期望副本数,并用 API Server 更新副本数,让系统自动贴合流量曲线。
具体案例:电商大促时订单量短时间翻倍,HPA 在几分钟内把核心服务从 20 个副本扩到 80 个副本;流量回落后再自动缩容,节省大批成本。
故障自愈
阶段:故障恢复
解决的问题:传统环境某个节点宕机,需要人工到场处理,恢复周期以小时计;K8s 的 Controller Manager 通过心跳发现节点失联,自动在其他健康节点重建 Pod。
具体案例:某游戏公司的云供应商节点突然宕机,kubelet 失联后,控制面自动把游戏大厅 Pod 迁移到剩余节点,玩家几乎无感。
Python 演示
import time class ReplicaSetSimulator: def __init__(self, desired, initial, max_step=2): self.desired = desired self.current = initial self.max_step = max_step def observe(self): return self.current def compute_delta(self): return self.desired - self.observe() def reconcile(self): diff = self.compute_delta() if diff > 0: action = min(diff, self.max_step) elif diff < 0: action = max(diff, -self.max_step) else: action = 0 self.current += action return action def main(): sim = ReplicaSetSimulator(desired=5, initial=1) for t in range(8): action = sim.reconcile() status = "已到达期望副本数" if sim.current == sim.desired else "继续调谐" print(f"t={t}: current={sim.current}, delta={sim.desired - sim.current:>+d}, action={action:>+d}, {status}") if sim.current == sim.desired: break time.sleep(0.2) if __name__ == "__main__": main()
def compute_delta(self):计算当前状态与期望状态的差值,这就是控制循环中的核心变量 Δ。def reconcile(self):执行一次调谐动作,对应 Controller Manager 每次循环所做的“纠偏”。action = min(diff, self.max_step)限制单次最大伸缩量,避免系统震荡。if sim.current == sim.desired: break当 Δ=0 时停止调谐,对应 K8s 中“已达到期望状态”。
常见误区
误区我以为执行 `kubectl apply` 后,YAML 会直接发送到工作节点的 kubelet,然后 kubelet 立刻创建容器。
正解kubectl apply 只是把资源对象交给 API Server。API Server 校验后写入 etcd,Controller 看到期望状态后创建副本,Scheduler 选定节点,最后 kubelet 才拉镜像并启动容器。整个过程是异步的,没有“直接推给 kubelet”这一步。
为何常见:用户看到容器最终启动了,就把“最终执行者”当成了“唯一执行者”,忽略了中间的控制面链条。
误区既然 etcd 存数据,那我可以直接连上去改几个 key 来修复 K8s 配置。
正解etcd 是集群的唯一真相源,但只有 API Server 能按规则写入。直接修改 etcd 会绕过认证、准入控制和版本校验,极易造成数据不一致,甚至让整个集群控制面崩溃。
为何常见:工程师习惯“连数据库改数据”的运维方式,却不理解 K8s 把写入权限收口到 API Server 的设计意图。
误区Scheduler 选定节点后,会直接在该节点上启动 Pod 进程。
正解Scheduler 只做“决策”,把 Pod 的节点归属写进资源对象;真正创建容器的动作由 kubelet 调用容器运行时完成。这就像排班经理只写排班表,楼层领班才实际去敲门保洁。
为何常见:调度和启动通常在很短时间内连续发生,感官上像同一个动作。
误区需要手动把 Deployment 副本数从 2 改成 5,然后 Controller Manager 会一次性创建 3 个 Pod。
正解Controller Manager 是持续运行的控制循环:不断观察当前数量、计算差值、发出变更请求。它不是被工程师触发的一次性工具,而是一个永远在“观察-比较-调谐”的自动化线程。
为何常见:用户只观察到“修改 YAML 后副本数变化”,却看不到后台一直在运行中的循环。
面试题
Q1. 以下哪个是 K8s 集群唯一的请求入口?
- A.调度器组件
- B.API 前端组件← 正确答案
- C.注册中心组件
- D.节点代理组件
答案:B。API Server 相当于酒店总台,所有 kubectl 和 SDK 请求都必须经过它。Scheduler 负责排班,etcd 负责存储,kubelet 负责执行,它们都不是用户请求的统一入口。
Q2. 在 K8s 中保存整个集群资源状态的是?
- A.容器运行时组件
- B.资源调度器组件
- C.键值仓库组件← 正确答案
- D.服务代理组件
答案:C。etcd 是 K8s 的“唯一真相源”,保存所有资源对象。容器运行时只负责跑容器,调度器负责选节点,代理负责网络转发。
Q3. 工作节点上常驻的关键组件是?
- A.API 服务组件
- B.控制循环组件
- C.节点代理组件← 正确答案
- D.键值存储组件
答案:C。kubelet 是典型的节点代理组件,工作节点通过它与 API Server 通信并管理 Pod。API Server、etcd、Scheduler 和 Controller Manager 都运行在控制面。
Q4. 声明式模型的核心思想是?
- A.逐步下发命令
- B.只看当前状态
- C.声明期望后自愈← 正确答案
- D.依靠人工修正
答案:C。声明式模型强调“告诉我你要什么,而不是怎么做”。用户声明期望状态,Controller 通过控制循环自动调谐,这就是自愈能力的关键。
Q5. 谁负责为 Pod 选择最合适的工作节点?
- A.控制器组件
- B.节点代理组件
- C.调度器组件← 正确答案
- D.API 服务组件
答案:C。Scheduler 负责对新 Pod 进行过滤和打分,最终决定调度到哪个节点;kubelet 只在节点上执行,Controller 负责调谐副本数。
Q6. 5 节点 etcd 集群写入数据至少需要几个节点确认?
- A.至少 1 个
- B.至少 2 个
- C.至少 3 个← 正确答案
- D.至少 4 个
答案:C。Raft 要求多数派确认,q=⌊5/2⌋+1=3。因此集群最多允许 2 个节点故障,相当于开投票会议必须过半数组人员到场。
Q7. 当控制器发现实际副本数大于期望副本数时,它通常会怎么做?
- A.修改期望副本值
- B.直接杀掉进程
- C.请求删除多余 Pod← 正确答案
- D.等待用户来处理
答案:C。控制器不会修改用户声明,而是通过 API Server 删除多余的 Pod,让当前状态收敛回期望状态。这对应控制循环中 Δ<0 时的调谐动作。
Q8. 控制面节点上包含哪些核心组件?
- A.API 服务组件← 正确答案
- B.键值存储组件← 正确答案
- C.调度器组件← 正确答案
- D.节点代理组件
答案:ABC。API Server、etcd、Scheduler、Controller Manager 都部署在控制面;kubelet 属于工作节点,不运行在控制面节点上。
Q9. 控制循环的经典步骤包括?
- A.观察当前状态← 正确答案
- B.对比期望状态← 正确答案
- C.执行调谐动作← 正确答案
- D.直接改用户配置
答案:ABC。控制循环是“观察→对比→调谐”的闭环:先观察当前状态,再和期望状态比较,最后执行动作拉平差距。它不会修改用户的 YAML 配置。
Q10. 关于 API Server 的说法,正确的是?
- A.它是集群唯一写入口← 正确答案
- B.它支持 Watch 订阅机制← 正确答案
- C.所有请求都经过它← 正确答案
- D.它直接运行用户容器
答案:ABC。API Server 是所有请求的必经之路,且只有它能写 etcd;它的 Watch 机制让 Scheduler、Controller 能实时感知变化。但它不直接管理容器,那是 kubelet 的职责。