ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Kubernetes集群架构与组件通信全解析:从控制平面到工作节点

2026/9/13 2:30:34 拓冰建站 浏览量
Kubernetes集群架构与组件通信全解析:从控制平面到工作节点 很多朋友第一次接触Kubernetes看到官方那张架构图第一反应往往是“这画的是个啥组件也太多了”。Control Plane、Node、etcd、kubelet、kube-proxy……每个名字都认识合在一起就不知道它们到底怎么协作。这篇文章我想从集群架构和组件通信的角度把我自己对Kubernetes的理解完整梳理一遍尽量用实际运维中会遇到的场景来讲而不是照搬官方文档。这套架构本质上就解决一个问题你声明想要的最终状态集群负责把它变成现实并且在节点宕机、资源不足、流量波动的时候持续维持这个状态。所有组件的分工、所有通信链路的设计都是围绕这个核心目标展开的。后面我会把每个组件的职责、组件之间的请求流转、高可用部署方式以及常见故障的排查思路都过一遍适合刚接触K8s想建立体系化认知的人也适合已经用了一段时间但某些细节还不清楚的运维和开发同学。1. 先看整体Kubernetes集群架构是怎么分层设计的在拆具体组件之前得先把整体分层搞清楚。Kubernetes集群从逻辑上分成两层控制平面Control Plane和数据平面Data Plane通常叫工作节点。这个分法不是随便画的它决定了整个系统在设计和运维上的所有走向。1.1 控制平面与工作节点的职责划分控制平面负责“决策”工作节点负责“执行”。控制平面不跑你的业务容器它只维护集群的期望状态哪些Pod应该存在、应该跑在哪个节点、副本数是多少、服务暴露方式是什么。你的每一次kubectl apply最终都是把请求打到控制平面的API入口。工作节点则不一样它上面跑的是真正的业务负载kubelet负责接收控制平面下发的指令容器运行时负责把容器拉起来kube-proxy负责让Pod能被访问。这个职责划分的一个直接好处是控制平面可以集中管理工作节点可以无限水平扩展。你扩展一万个节点控制平面组件依然是那一组只是压力变大而已。这也是为什么在规划K8s集群时控制平面节点通常和工作节点分离部署不建议混部尤其不建议把etcd和业务容器放在一起。1.2 声明式API整个架构运转的底层逻辑理解了分层还得理解Kubernetes最核心的设计哲学声明式API。你告诉集群“我要3个nginx副本”集群就通过一系列组件协作去达成这个状态。整个过程不需要你关心具体怎么创建、怎么调度、怎么健康检查你只需要维护好YAML这个“期望状态”的载体。这套机制能成立关键在list-watch模式。控制平面的组件包括工作节点上的kubelet不会反复轮询API Server而是通过HTTP长连接监听资源的变化。一旦你apply了一个DeploymentAPI Server把数据写进etcd所有关心这个资源类型的组件都能立刻收到变更事件然后各自执行自己的那部分工作。这种事件驱动机制比定时轮询优雅得多也是整个集群能保持高效协作的基础。2. 控制平面组件逐个拆解集群的“大脑”如何运转控制平面一般包含四个核心组件kube-apiserver、etcd、kube-controller-manager、kube-scheduler。有的集群还部署了cloud-controller-manager用于对接公有云的负载均衡、存储卷等能力。这四个组件各管一摊但协作非常紧密。2.1 kube-apiserver一切通信的入口API Server是整个集群唯一的入口任何对集群状态的查询、修改都必须经过它。你把kubectl、kubelet、controller-manager、scheduler想象成不同的客户它们不直接跟etcd对话全部通过API Server中转。这样设计最直接的好处是安全策略可以集中收口——认证、授权、准入控制都在这一层完成。API Server处理一个请求的完整链路是认证Authentication确认你是谁授权Authorization确认你能不能干这件事准入控制Admission Control检查有没有额外的策略限制。这三个环节缺一不可。比如你创建Pod时如果配额不够就是准入控制阶段拦下来的根本不会写入etcd。运维上要特别注意API Server的QPS和并发连接数。有一次我在压测环境里发现kubectl get nodes都要卡好几秒排查下来是某个组件写了全量的list请求刷爆了API Server。后来我在API Server的启动参数里加了--max-requests-inflight限制同时让业务方改用informer做增量监听才把压力降下来。2.2 etcd集群状态的唯一存储etcd是Kubernetes的“数据库”保存着所有集群数据Pod、Service、ConfigMap、Secret、Deployment等等。它是一个分布式键值存储底层基于Raft共识算法多个节点之间通过投票选举Leader来保证数据一致性。这里有个常见误区很多人以为etcd只存配置实际上Pod的运行状态、节点的心跳信息、事件记录全都存在etcd里。集群出问题的时候etcd往往是最先暴露问题的那个。比如我在生产环境遇到过etcd频繁产生leader切换排查发现是磁盘IO延迟太高Raft心跳超时导致的。那次之后我坚持把etcd的数据目录放在单独的SSD盘上并开启--wal-sync确保每个写请求都落盘成功。etcd的性能和稳定性直接决定集群的稳定性。官方建议etcd数据盘至少SSD网络延迟保证在10ms以内并且严格控制集群规模。一个超过2万Pod的大集群etcd的写入压力会明显增大需要做好分集群规划或者开启压缩功能。2.3 kube-controller-manager把声明状态拉向期望状态controller-manager里跑着一堆控制器每个控制器负责一种资源的状态调节。比如Deployment控制器负责维护副本数Node控制器负责节点健康检查Namespace控制器负责清理删除命名空间。它们的逻辑本质都是一个循环从API Server获取当前状态对比期望状态然后执行操作让当前状态向期望状态收敛。举一个最常见的例子你把Deployment的副本数从3改成5Deployment控制器监听到这个变更就会创建2个新的ReplicaSetReplicaSet控制器看到副本数不满足就会调用API Server创建Pod。你说这么多控制器不累吗它们的监听机制是高度隔离的每个控制器只关心自己对应的资源类型通过informer机制增量更新。需要注意的一点是controller-manager本身就是单点的因为它内部使用选主机制保证同时只有一个实例在工作。高可用部署的时候你可以多副本跑但同一时刻只有一个实例真正干活其余处于standby状态。2.4 kube-scheduler决定Pod去哪个节点scheduler的任务很简单但也很关键为新创建的Pod挑选一个最合适的节点。它不是随机选的而是一套预选优选的流程。预选阶段会过滤掉不满足条件的节点比如资源不够、节点有污点、端口冲突优选阶段会对剩余节点打分综合考虑CPU和内存的剩余量、Pod分布情况、亲和性规则等分数最高的节点胜出。调度策略里有几个经常被忽视的细节。一是资源请求requests和资源限制limits要合理设置如果你所有Pod的requests都写得极低调度器就会认为节点很空闲结果运行时内存爆掉二是亲和性规则不要滥用我看到有团队给每个Pod都加了节点亲和性结果调度越来越慢因为预选阶段要遍历大量规则三是binpack和spread两种策略的取舍测试环境希望Pod分散在不同节点避免单点故障而成本敏感的环境则希望尽量打满节点。3. 工作节点组件解析真正跑业务的地方别忽视工作节点上的组件虽然只有三四个但任何一个出问题业务就直接受影响。3.1 kubelet节点上的“管家”kubelet是每个节点上最核心的代理组件它负责管理本节点的Pod生命周期。kubelet会持续监听API Server发现有Pod被调度到本节点就调用容器运行时创建容器然后通过存活探针livenessProbe和就绪探针readinessProbe检查容器健康状态状态异常时根据策略重启或摘除流量。我排查过最多的kubelet问题就是证书过期。kubelet的证书默认有效期是一年到期后如果没开启自动续期节点会直接NotReady。判断方法很简单kubectl get nodes看状态如果一直是NotReady登录节点用journalctl -u kubelet看日志如果有certificate expired相关报错那基本就是这个原因。解决方法是开启kubelet的证书轮换加上--rotate-certificatestrue和--rotate-server-certificatestrue。磁盘压力也是kubelet的高频问题。kubelet会监控节点磁盘使用率超过阈值默认85%会把节点标记为磁盘压力然后开始驱逐Pod。有一段时间我们的日志Pod经常被驱逐排查后发现是容器日志没有设置轮转导致/var/log目录暴涨。在containerd配置里加上max_size和max_files之后这个问题就没再出现过。3.2 kube-proxy流量转发与负载均衡的细节kube-proxy解决的核心问题是当客户端访问Service的ClusterIP时流量怎么转发到后端的Pod。早期版本默认使用iptables模式每条Service规则会生成一串iptables链流量按规则匹配到对应的Pod IP。这个模式实现简单但有个明显缺点当集群里有上千条Service时iptables规则数量膨胀更新延迟明显会出现流量转发抖动。后来ipvs模式逐渐成为主流。ipvs是内核内置的负载均衡模块它用哈希表而不是链式匹配更新速度和转发性能都优于iptables。开启方式很简单在kube-proxy的启动参数里加--proxy-modeipvs。但在实际使用中kube-proxy有个需要特别注意的点它只做转发不做健康检查。如果某个Pod挂了但kubelet没及时更新Endpoints请求还是会被转发到那个坏Pod上。所以Service的流量可靠性是依赖kubelet的探针机制和Endpoints控制器联动保障的要保证存活探针和就绪探针配置合理探针本身不要太宽松也不要太激进。3.3 容器运行时Pod的底层执行者容器运行时负责真正创建、启动、销毁容器。Kubernetes通过CRIContainer Runtime Interface接口对接运行时目前最主流的是containerdDocker作为底层运行的场景正在快速减少。containerd相比Docker的优势是资源占用更小、启动更快而且它是直接面向K8s设计的不需要经过Docker的守护进程和CLI接口。我在迁移集群时从Docker切到containerd容器启动速度有明显提升节点内存占用也降了不少。在配置containerd时有几个参数值得关注。比如SystemdCgroup这个参数如果设为false容器内的cgroup管理方式跟节点的systemd不一致可能会导致资源统计不准和偶发性的OOM。所以生产环境一定要确保SystemdCgrouptrue。另外镜像仓库的加速配置也很重要我通常会在containerd的registry配置里加上多个镜像源避免拉大镜像时超时。4. 组件之间怎么通信一条请求的完整生命周期把每个组件单独列出来之后最关键的是把它们串起来理解。组件之间不是各自为战而是一整条配合紧密的链路。这一节我讲两条最常见的链路一条是创建Deployment另一条是Pod访问Service。4.1 创建Deployment的完整内部流转当你执行kubectl apply -f deployment.yaml这条链路会依次经过以下组件kubectl先把YAML解析成Deployment对象通过HTTPS发送到API Server的/deployments接口。API Server完成认证、授权、准入检查后把Deployment对象序列化写入etcd。Deployment控制器通过informer监听到这个新对象发现期望副本数比如3远大于当前副本数为0于是创建对应的ReplicaSet对象。ReplicaSet控制器监听到新ReplicaSet发现副本数不足开始创建Pod对象实际上是创建Pod的期望状态。Scheduler监听到新Pod且nodeName字段为空进入调度流程预选优选后为Pod选定一个节点并把nodeName写回Pod。kubelet监听到nodeName等于自己节点名的Pod开始调用containerd拉镜像、创建容器。kubelet通过探针确认容器就绪后把Pod状态更新为Running同时更新Pod的IP和端口信息。这条链路里任何一环卡住最终表现都是Pod一直Pending或者ContainerCreating。所以排障时先看Pod状态根据状态去定位卡在哪个组件是scheduler没调度、还是镜像拉不下来、还是探针没过。4.2 Pod访问Service的流量路径当一个Pod需要访问另一个服务时最常见的方式是通过Service的ClusterIP。数据包的流转路径是这样的Pod内的应用发起连接到ClusterIP:Port数据包先到达节点的网络栈kube-proxy生成的iptables或ipvs规则把目标地址DNAT成后端某个Pod的IP然后按路由规则转发到对应节点。这里有个容易踩坑的点跨节点访问时如果网络插件用的是flannel的VXLAN模式数据包是封装在UDP里走的延迟会比宿主机直连高一些。我做过压测VXLAN模式下的P99延迟比hostNetwork直接访问高大约0.3到0.5毫秒。对于毫秒级超时的接口这个开销不容忽视。如果对延迟很敏感可以考虑Calico的BGP模式数据包直接走三层路由不经过隧道封装。4.3 集群内部DNS与插件组件除了核心组件Kubernetes集群还依赖一些附加组件才能干活最典型的就是CoreDNS。CoreDNS为集群提供DNS解析服务Pod访问Service时可以直接用服务名比如my-service.namespace.svc.cluster.local而不需要记ClusterIP。CoreDNS本身也是跑在Pod里的它通过Service对外提供服务。所以这里有个有意思的循环依赖CoreDNS的Pod要能启动需要容器运行时要能被集群内访问需要kube-proxy配置好规则。排查DNS问题时通常先确认CoreDNS Pod是否Running然后用nslookup命令测试解析是否正常。我自己有个习惯在创建集群时就把CoreDNS的副本数设为2以上并把它调度到不同节点。因为DNS是整个集群服务发现的基础它挂了所有通过服务名互访的业务都会受影响。5. 高可用部署与关键配置实操理解了架构之后实际部署高可用集群是一个必须经历的环节。这一节我分享一些我实际操作中验证过的配置经验。5.1 控制平面高可用怎么搭控制平面的高可用核心有三个点API Server多副本、etcd多节点、组件选主机制。API Server本身是无状态的你可以在三台控制平面节点上都部署kube-apiserver前面挂一个负载均衡器可以是Nginx、HAProxy或者云厂商的LB把请求分发到三台节点上。etcd则部署三节点或五节点集群通过Raft协议保证数据一致性。controller-manager和scheduler虽然在每个控制平面节点上都有进程但同一时刻只有一个处于active状态其他都是standby。搭建HA集群时有一个部署顺序的问题。最佳实践是先用kubeadm的配置文件同时初始化三个控制平面节点然后再加入工作节点。如果先加入工作节点再扩展控制平面往往需要处理证书和配置同步的问题比较折腾。5.2 组件参数与资源规划建议控制平面节点的硬件规划我一直遵循一套比较稳妥的标准4核8GB起步etcd单独给2核4GB以上磁盘务必是SSD。生产环境建议8核16GB以上因为随着集群规模增长API Server和etcd对CPU和内存的需求都会明显增加。工作节点按业务量规划但容器运行时和kubelet会占用一定的系统资源经验值是每台节点预留1核2GB给系统组件和内核开销剩余资源才分配给业务Pod。这里重点提一下API Server和etcd的几个启动参数。API Server的--max-requests-inflight建议设成300到500--max-mutating-requests-inflight设成100到200超过这个量的请求会直接排队。etcd的--quota-backend-bytes默认是2GB生产建议调到8GB避免因为空间不足导致集群不可写同时开启--auto-compaction-modeperiodic和--auto-compaction-retention1h定期清理历史数据。5.3 网络插件的选型与部署网络插件CNI是整个集群里最不好替换的组件选型一定要谨慎。我在多个环境里对比过Flannel简单、易排查、适合中小集群Calico功能全面支持网络策略NetworkPolicy适合对安全隔离和跨网段有要求的场景Cilium性能最好基于eBPF但排查难度相对更高。我目前的主力环境用的是Calico原因是对NetworkPolicy的支持非常成熟。配置NetworkPolicy时要注意它会按命名空间和标签做白名单控制不配置的情况下默认是允许所有流量。我自己遇到过一个典型案例某天业务方反馈两个服务之间突然访问不通排查发现是有人新建了一个NetworkPolicy把目标服务的端口给封了但源服务没被放行。网络插件部署后不要在集群里随意更换因为每个插件会写入自己的CNI配置和IP管理数据切换过程需要重建所有Pod风险极高。如果一定要更换先规划好Pod IP段和网络策略的兼容性建议在测试环境完整演练一遍再上生产。6. 排障实录那些年我踩过的Kubernetes组件坑最后一部分梳理一些我在实际运维中遇到的问题和处理思路。每个问题都是真实踩过的坑处理过程和排查思路分享出来希望对你有参考价值。6.1 kubelet一直NotReady怎么办现象kubectl get nodes看到节点NotReady登录节点后发现kubelet服务在反复重启。排查步骤先用journalctl -u kubelet -f看实时日志通常能直接看到报错。常见原因有三个一是证书过期报错信息里会出现certificate has expired这个直接检查/var/lib/kubelet/pki目录下证书有效期然后开启自动轮换二是磁盘压力导致kubelet驱逐日志里会显示eviction manager triggered这时候看df -h检查/var/lib/docker或者/var/lib/containerd目录是否被打爆三是容器运行时异常containerd服务挂了需要分别排查containerd的日志和socket状态。6.2 API Server响应越来越慢现象kubectl命令明显卡顿但节点资源占用都不高。这类问题排查的关键点在于区分是API Server处理不过来还是etcd响应慢了。抓一下API Server的metrics重点关注etcd请求延迟和apiserver_request_duration_seconds。如果延迟集中在etcd去检查etcd节点的磁盘IO和WAL同步时间如果集中在API Server自身看--max-requests-inflight是否被打满有没有大量大对象的list请求。我遇到过一次很典型的案例某个服务的高频job每秒钟调用API Server列出集群所有Pod全量list数量几万个直接把API Server的QPS打满。后来改成用watch做增量更新API Server的CPU占用直接从80%降到了10%。6.3 etcd性能告急集群抖动明显现象集群时不时的出现Pod调度延迟、Evicted事件、甚至API连接超时。etcd是全集群的“神经系统”它一抖动所有组件都会察觉到。排查时要区分是网络问题还是磁盘问题。用etcdctl endpoint health检查集群健康用etcdctl endpoint status看每个节点的状态。如果是网络分区导致leader切换检查节点之间的网络延迟和丢包如果是单节点磁盘IO过高看iostat确认是否有其他进程抢占IO。我个人在维护etcd时有一条硬性要求etcd数据目录所在磁盘的写延迟必须低于10ms一旦超过必须马上处理。如果是共享磁盘的宿主机考虑给etcd单独挂盘。6.4 网络插件异常导致Pod间通信失败现象所有Pod状态正常但Pod之间访问不通ping无响应。先确认网络插件Pod的状态比如calico-node是否都是Running。然后从节点上手动创建一个测试Pod进入Pod后用ip addr确认IP地址配置是否正确ping一下网关和对端Pod IP。如果IP通但Service访问不通问题大概率在kube-proxy的iptables规则如果IP不通需要检查网络插件的路由表尤其是跨节点通信时VXLAN隧道的状态。还有一个常见问题是MTU不匹配。云环境下如果底层网络MTU是1500而VXLAN隧道封装后要留出额外开销MTU不匹配会导致大包不通、小包正常。排查时用ping -s 1400测试大包如果小包能通大包不通大概率是MTU配置问题。最后的几点心得做了这么多年Kubernetes集群的运维和管理我最大的体会是K8s架构本身并不复杂复杂的是它把很多分布式系统的经典问题都融在了一起——一致性问题、调度问题、网络问题、存储问题每个组件单独看都能理解难的是出问题时怎么快速定位到具体组件。我的习惯是遇到任何集群异常先看Kubernetes的事件记录kubectl get events --sort-by.lastTimestamp事件会告诉你组件之间协作的每个细节。大部分问题都能从事件流转里找到线索不用一上来就去翻各种日志。另外监控和告警一定要尽早做特别是API Server延迟、etcd延迟、kubelet状态这三项它们往往是最先暴露问题的。这套架构设计和组件协作的机制值得你花时间去吃透它会在你排查问题时事半功倍。