2023年,全球云原生基金会(CNCF)的调研显示,96%的企业正在使用或评估 Kubernetes。但同一批受访者里,能准确画出控制平面(Control Plane)数据流向的人不到12%。
这个差距很有意思。我们用K8s部署应用像用遥控器开电视——按个按钮,事情就发生了。但电视怎么换的台,信号从哪来,大多数人没概念。
今天把遥控器拆开,看看7个核心组件怎么协作,让一个容器从"本地代码"变成"全球可访问的服务"。
控制平面:7个人的指挥部
Kubernetes的架构分两层:控制平面(Control Plane)和节点(Node)。前者是大脑,后者是手脚。
控制平面由7个核心组件构成,它们全部跑在Master节点上,但分工极其明确。
API Server(应用程序接口服务器)是唯一对外的门。所有操作——无论是你用kubectl敲命令,还是其他组件内部通信——都必须经过它。它不直接干活,只负责"收条子"和"发通知"。
etcd是个键值存储数据库,相当于K8s的账本。整个集群的状态——哪些Pod(最小部署单元)在哪运行、配置是什么——全写在这里。API Server读写etcd,其他组件只读不写。
Scheduler(调度器)专门做一道选择题:新创建的Pod该放到哪个节点?它看资源余量、亲和性规则、污点容忍度,最后给出一个最优解。但注意,Scheduler只决定,不执行。
Controller Manager(控制器管理器)是一堆控制器的集合。每个控制器盯着一种资源:Deployment控制器确保副本数正确,Node控制器发现节点宕机就迁移Pod,Endpoint控制器维护服务发现列表。它们像7×24小时的值班员,发现"期望状态"和"实际状态"不一致就触发修复。
Cloud Controller Manager(云控制器管理器)是后来拆出来的。早期这些代码揉在Controller Manager里,2018年单独成组件。它专门对接云厂商API——创建负载均衡器、挂载云盘、管理节点生命周期。用了自建机房的团队,这个组件可以直接关掉。
最后两个是DNS和Dashboard,一个管服务发现,一个管可视化。严格来说不算核心,但默认都会装。
节点:干活的4个苦力
控制平面做决定,节点(Node)执行。每个节点上跑着4个关键组件。
Kubelet是节点的"监工"。它接收API Server的指令,指挥容器运行时(Container Runtime)真正创建或销毁容器。容器运行时早期是Docker,现在默认换成containerd——更轻量,启动速度从秒级降到毫秒级。
Kube-proxy负责网络。它维护节点上的iptables(或IPVS)规则,把Service(服务)的虚拟IP映射到实际Pod的IP。用户访问一个Service,Kube-proxy决定流量该分给哪个后端Pod。
容器运行时和Pod是最后两个。前者是干活的工具,后者是K8s调度的最小单位——一个Pod里可以塞一个或多个容器,共享网络和存储。
这里有个反直觉的设计:Pod是"临时"的,IP会变,所以才有Service这层抽象。Service的IP固定,背后Pod随便换,用户无感知。
一个请求的全旅程:从kubectl到容器
假设你执行kubectl apply -f deployment.yaml,后面发生了什么?
第一步,kubectl把你的YAML文件转成HTTP请求,发给API Server。API Server先做认证鉴权——你是谁?能干嘛?
第二步,API Server把这份"期望状态"写入etcd,然后给Scheduler发通知:有个新Pod需要安排。
第三步,Scheduler从etcd读出所有节点信息,算一遍分数,选出最优节点。它把决定写回etcd,但不直接通知那个节点。
第四步,目标节点上的Kubelet一直在"监听"etcd(通过API Server)。发现有个Pod被分配给自己了,它就调用containerd拉镜像、创容器、起进程。
第五步,Kubelet把实际状态回写etcd。Controller Manager里的Deployment控制器发现"期望3个副本,实际3个运行",状态一致,无事发生。
第六步,Endpoint控制器发现新Pod的IP,更新Service的后端列表。Kube-proxy感知到变化,刷新本节点的转发规则。
第七步,用户通过Service IP访问应用,流量被Kube-proxy负载均衡到某个Pod。全程大概3-5秒,取决于镜像大小。
为什么这套设计能赢
2014年Kubernetes开源时,Docker Swarm和Mesos都在做容器编排。K8s能杀出来,核心在于"声明式API"(Declarative API)的设计哲学。
你不是对系统喊"给我启动3个容器",而是写一份YAML说"我希望始终维持3个容器运行"。Controller们自己去比对、去修复、去兜底。这种"最终一致性"的模型,比命令式更适合大规模分布式系统——节点宕机、网络分区、容器崩溃,都能自动恢复。
etcd的选型也很关键。它用Raft协议保证强一致性,单集群能支撑每秒数万次写入。2019年etcd从CNCF毕业,成为K8s之外独立的基础设施项目。
另一个被低估的设计是CRD(自定义资源定义,Custom Resource Definition)。K8s把"资源"这个概念抽象到极致——Pod、Service是资源,Istio的虚拟服务、Prometheus的监控规则也能变成资源。Operator模式(运维自动化模式)由此诞生:你把运维经验写成控制器,K8s帮你自动执行。
Google的Borg系统运行了15年,K8s是它的开源精神续作。但Borg的代码没开源,K8s的API设计却成为事实标准。AWS的EKS、Azure的AKS、阿里云的ACK,底层都是这套组件,只是托管程度不同。
2024年,K8s的代码库已经超过300万行,但核心控制平面的7个组件基本没变。变的只是周边——Gateway API替代Ingress,Sidecar模式被Ambient Mesh挑战,eBPF加速网络转发。这些新东西都在K8s的"插件接口"上生长,不碰核心。
有个细节很有意思:Kubelet和API Server之间的通信,默认用HTTP/2长连接。这样Kubelet能实时" watch "(监听)资源变化,而不需要轮询。这个设计省了大量带宽,也让调度延迟从秒级降到毫秒级。但代价是连接数爆炸——一个千节点集群,API Server上挂着几千条长连接,内存压力不小。
云厂商的托管方案(Managed Kubernetes)本质上是在帮你扛这个复杂度。EKS的API Server自动扩缩容,etcd用多可用区冗余,你只管提交YAML。但账单上的"控制平面费用"每月几百美元起步——免费的东西,最贵的是认知。
如果你今天才开始学K8s,建议从kubectl debug和crictl(容器运行时命令行工具)这两个命令入手。前者能直接进容器抓现场,后者能在Kubelet挂掉时手动操作containerd。生产环境出问题,往往是这两个工具救场。
最后一个问题留给你:当K8s已经成为"基础设施的基础设施",下一代编排系统会是什么样子?是WebAssembly(一种字节码格式)的轻量化运行时,还是完全无服务器的抽象?Google内部已经在实验Borg的下一代,但代码依然不会开源。我们能看到的,只有K8s API的兼容层越来越厚,迁移成本越来越高——这算不算另一种形式的 vendor lock-in(厂商锁定)?
热门跟贴