一、K8s架构设计
K8s的核心架构遵循“主从架构”(也叫Master-Worker架构),整体分为两大板块——控制平面(Control Plane)和工作节点(Node)。简单来说,控制平面是集群的“大脑和指挥中心”,负责全局决策、资源调度和状态管理,不直接运行业务容器;工作节点是集群的“手脚和执行单元”,是业务容器的实际运行载体,负责接收并执行控制平面的所有指令,同时反馈自身运行状态。
这种分离设计的优势十分明显,也是K8s能适配不同规模场景的关键:一方面实现了“决策与执行”的解耦,控制平面专注于集群整体的管理和调度,不参与具体的容器运行,工作节点专注于容器的启动、运行和监控,两者互不干扰,大幅提升集群的稳定性和可扩展性;另一方面,控制平面和工作节点均可独立扩容——当业务量增长,需要更多容器运行时,只需增加工作节点数量;当集群规模扩大,需要提升调度和管理能力时,只需扩展控制平面组件,既能应对互联网大厂上万节点的大规模集群需求,也能适配中小企业几台节点的轻量化部署场景。
从部署规模来看,一个完整的K8s集群,至少需要1个控制平面节点和1个工作节点,这种单节点控制平面的部署方式,适合开发、测试等非生产环境,优点是部署简单、资源占用少,缺点是存在单点故障,一旦控制平面节点故障,整个集群将无法正常运行。而在生产环境中,为了保证高可用,控制平面通常会跨3台机器部署(形成高可用集群),工作节点也会部署多个,通过多节点冗余,避免单点故障导致整个集群瘫痪,确保业务的连续性。
二、控制平面:决策与调度中心
控制平面的核心作用是“掌握全局、统筹决策”,它不直接运行容器,而是通过各类组件的协同配合,实现集群状态的实时监控、资源的合理调度和异常的自动修复。控制平面包含4个核心组件(云环境下还会增加cloud-controller-manager组件),每个组件都有明确的分工,缺一不可,且组件之间通过kube-apiserver实现通信,确保指令和数据的统一流转。
1. kube-apiserver:集群入口与网关
kube-apiserver是K8s集群的“前端门户”,也是所有组件之间通信的唯一桥梁,没有它,整个集群就会陷入“瘫痪”状态——无论是我们日常使用kubectl命令操作集群(如创建Pod、查看节点状态),还是控制平面内部组件(如kube-scheduler、kube-controller-manager)之间的交互,亦或是工作节点上的kubelet与控制平面的通信,都必须通过kube-apiserver,它相当于集群的“通信枢纽”。
它的核心职责主要有4点:一是接收并验证所有请求,包括用户的操作请求(如kubectl命令)、组件的状态上报请求等,会对请求的合法性进行严格校验,比如验证用户是否有操作权限、请求的配置格式是否正确,过滤掉非法请求,避免集群被恶意操作或错误配置影响;二是分发请求,将合法请求分发到对应的组件进行处理,比如调度请求分发到kube-scheduler,状态维护请求分发到kube-controller-manager;三是数据同步,将集群的所有状态变化(如Pod创建、节点故障)同步到etcd中进行持久化存储;四是提供API接口,支持外部系统(如监控平台、CI/CD工具)通过API与K8s集群交互,实现集群的自动化管理。
此外,kube-apiserver采用无状态设计,这意味着它本身不存储任何集群数据,所有数据都依赖etcd,这种设计的好处是支持水平扩展——当集群请求量增大时,只需部署多个kube-apiserver实例,配合负载均衡器(如Nginx、HAProxy)实现请求分发,既能提升集群的并发处理能力,也能避免单一kube-apiserver实例故障导致的集群不可用,实现高可用部署。值得注意的是,kube-apiserver是控制平面中唯一能直接与etcd交互的组件,这就保证了集群数据访问的统一性和安全性,避免多组件直接操作etcd导致的数据不一致、数据泄露等问题。
2. etcd:集群分布式数据集合
etcd是一个基于Raft一致性算法的分布式键值数据库,相当于K8s集群的“数据库”,负责持久化存储集群的所有核心数据,集群中所有组件的状态、配置信息,最终都以etcd中的数据为准,任何组件的状态变更,都必须同步到etcd中,确保所有组件获取到的集群状态是一致的。
etcd存储的数据类型主要包括:集群的基本配置(如集群名称、版本信息)、节点信息(如节点IP、状态、资源配置)、Pod配置(如镜像地址、资源需求、重启策略、挂载卷信息)、Service规则(如端口映射、负载均衡策略)、密钥和配置项(如密码、环境变量、配置文件)、集群状态(如Pod运行状态、节点健康状态)等,几乎涵盖了集群运行所需的所有核心数据。
etcd的核心优势是强一致性和高可用,这也是它能成为K8s集群“唯一真相来源”的关键:通过Raft一致性算法实现多节点数据同步,etcd集群通常由多个节点组成,其中一个节点作为主节点(Leader),负责接收所有数据变更请求(如写入、修改、删除),并将变更同步到所有从节点(Follower);所有从节点会实时同步主节点的数据,确保集群中所有节点的数据一致。当主节点故障时,从节点会通过Raft选举机制,在规定时间内选举出一个新的主节点,继续处理数据变更请求,确保即使部分节点故障,数据也不会丢失、服务也不会中断,保障集群的稳定性。
在生产环境中,etcd的部署有明确的规范:通常部署3个或5个节点(必须是奇数节点),这是因为Raft算法需要超过半数的节点同意才能完成主节点选举和数据同步,避免出现“脑裂”问题(即多个节点同时认为自己是主节点,导致数据不一致)。同时,etcd对硬件资源要求较高,尤其是磁盘IO性能,因为它需要频繁写入和读取数据,磁盘IO性能直接影响集群的响应速度,因此建议使用SSD磁盘部署etcd,并且需要制定完善的备份计划(如定时备份etcd数据),防止数据丢失,避免集群故障后无法恢复。
3. kube-scheduler:集群资源调度中心
当集群中出现新的、未指定运行节点的Pod(状态为Pending)时,它会根据预设的调度策略,结合集群的实际情况(如节点资源负载、Pod资源需求、亲和性规则等),选择最合适的工作节点来运行这个Pod,确保资源的合理利用,同时满足业务的运行需求。
调度过程主要分为两步,这两步环环相扣,确保调度结果的合理性和最优性:第一步是“过滤(Filtering)”,也叫“预选”,kube-scheduler会遍历集群中所有健康的工作节点,根据Pod的资源需求和约束条件,排除不满足条件的节点。比如Pod需要2核CPU、4GB内存,而某个节点的剩余CPU只有1核、剩余内存只有2GB,那么这个节点就会被过滤掉;再比如Pod设置了节点亲和性(只能运行在特定标签的节点上),那么没有该标签的节点也会被过滤掉。常见的过滤规则包括资源需求过滤、节点亲和性过滤、污点容忍过滤、端口冲突过滤等,经过过滤后,会得到一个“可用节点列表”。
第二步是“打分(Scoring)”,也叫“优选”,kube-scheduler会对过滤后的可用节点进行打分,打分范围为0-100分,得分越高,说明该节点越适合运行当前Pod。打分的维度有很多,默认的打分策略包括:节点资源利用率(资源利用率越低,得分越高,避免节点过载)、节点负载均衡(尽量让Pod均匀分布在各个节点上,避免部分节点负载过高,部分节点闲置)、Pod亲和性/反亲和性(如果Pod有亲和性规则,优先选择能满足亲和性的节点)、节点就绪时间(优先选择就绪时间长、运行稳定的节点)等。打分完成后,kube-scheduler会选择得分最高的节点作为目标节点,完成调度决策。
需要注意的是,kube-scheduler只负责“决策Pod该调度到哪个节点”,不参与Pod的实际创建和运行;调度结果会通过kube-apiserver写入etcd,然后由目标节点上的kubelet感知到调度结果,执行后续的容器创建、启动操作。此外,kube-scheduler还支持自定义调度策略,对于一些特殊业务场景(如GPU密集型业务、高IO业务、低延迟业务),默认的调度策略可能无法满足需求,开发者可以通过编写自定义调度器,实现符合业务需求的调度逻辑,进一步提升集群的资源利用率和业务运行效率。
4. kube-controller-manager:集群的状态维护中心
kube-controller-manager的核心职责是“监控集群状态,修正偏差”,它运行着一系列“控制循环(Controller Loop)”,这些控制循环会实时监听集群的实际状态,对比用户定义的期望状态(如Pod的副本数、节点的健康状态),一旦发现实际状态与期望状态存在偏差,就会自动执行相应的操作,将集群拉回到期望状态,这也是K8s“自愈能力”的核心来源——不需要人工干预,就能自动修复集群中的异常问题。
从逻辑上讲,每个控制器都是一个独立的进程,每个控制器负责管理集群中的某一类资源或某一种场景,但为了降低部署和维护的复杂性,这些控制器被编译到同一个可执行文件中,以同一个进程的形式运行,这就是kube-controller-manager。常见的控制器包括以下几种,覆盖集群管理的各个场景:
Node控制器(Node Controller):实时监听节点的状态,当某个节点故障(如网络中断、机器宕机),无法向控制平面上报状态时,Node控制器会检测到这一情况,将该节点标记为不可用(NotReady),并通知kube-scheduler,避免将新的Pod调度到该节点上;同时,会将该节点上的Pod重新调度到其他健康节点,确保业务不中断。
Job控制器(Job Controller):负责管理一次性任务的Pod,当用户创建一个Job(如执行一次数据备份、运行一次脚本)时,Job控制器会确保指定数量的Pod成功运行并完成任务,任务完成后,会自动终止Pod;如果Pod运行失败,会根据配置的重试策略重新启动Pod,直到任务完成。
EndpointSlice控制器(EndpointSlice Controller):负责维护Service与Pod的关联关系,Service是K8s中用于暴露Pod服务的组件,EndpointSlice控制器会实时监听Pod的创建、销毁、迁移,动态更新Service对应的EndpointSlice(记录Pod的IP和端口),确保外部请求能通过Service正确转发到对应的Pod。
ServiceAccount控制器(ServiceAccount Controller):负责管理集群中的服务账户,当用户创建一个新的命名空间时,ServiceAccount控制器会自动为该命名空间创建一个默认的ServiceAccount,Pod可以通过ServiceAccount获取集群的访问权限,实现对集群资源的操作(如读取Pod信息、创建ConfigMap)。
副本控制器(ReplicaSet Controller):负责维护Pod的副本数,当用户创建一个ReplicaSet(或Deployment,Deployment依赖ReplicaSet),指定了Pod的期望副本数时,副本控制器会实时监控Pod的运行状态,如果实际副本数少于期望副本数,会自动创建新的Pod;如果实际副本数多于期望副本数,会自动删除多余的Pod,确保Pod的副本数始终与期望一致。
除了上述常见的控制器,kube-controller-manager还包含Namespace控制器、ConfigMap控制器、Secret控制器等,这些控制器协同工作,共同维护集群的稳定运行,确保集群的实际状态始终符合用户的期望。
5. cloud-controller-manager:云平台集成的控制器
cloud-controller-manager是K8s控制平面的可选组件,仅在云环境(如阿里云、AWS、腾讯云等公有云平台)中部署,本地环境、私有集群(如企业内网部署的集群)通常不需要部署该组件。它的核心作用是嵌入特定于云平台的控制逻辑,将K8s集群与云平台的API进行对接,实现与云平台资源的联动,让K8s集群能充分利用云平台的基础设施资源。
具体来说,cloud-controller-manager的主要功能包括:一是创建云平台负载均衡器,当用户在K8s集群中创建一个LoadBalancer类型的Service时,cloud-controller-manager会调用云平台的API,自动创建一个云平台的负载均衡器(如阿里云的SLB、AWS的ELB),并将Service的端口与负载均衡器关联,实现外部流量的负载分发;二是设置云平台路由,负责配置K8s集群节点与云平台网络的路由规则,确保节点之间、节点与外部网络的通信通畅;三是管理云平台的存储资源,当用户创建一个使用云平台存储的PersistentVolume(持久化卷)时,cloud-controller-manager会调用云平台的API,自动创建对应的云存储资源(如阿里云的OSS、AWS的S3),并将其挂载到Pod中,满足业务的持久化存储需求;四是节点生命周期管理,与云平台的API联动,实现节点的自动创建、销毁和修复,比如当某个节点故障时,cloud-controller-manager可以调用云平台API,自动创建一个新的节点,替代故障节点,进一步提升集群的高可用性。
三、工作节点:集群执行单元,运行容器的载体
工作节点(Node)是实际运行容器应用的机器,可以是物理机,也可以是虚拟机,每个工作节点都受控制平面的管理,接收控制平面的指令,执行容器的创建、启动、停止、重启等操作,同时实时向控制平面上报自身的运行状态和容器的运行状态。每个工作节点上都运行着3个核心组件,这3个组件协同工作,确保Pod能正常运行,业务能稳定提供服务。
1. kubelet:节点容器管家
kubelet是运行在每个工作节点上的代理程序,也是工作节点与控制平面通信的核心组件,它的核心职责是“保证Pod中的容器按预期运行”,相当于每个工作节点上的“管家”,负责管理该节点上所有Pod和容器的生命周期。
kubelet的主要工作内容包括:一是接收指令,实时监听kube-apiserver,获取调度到本节点的PodSpec(Pod的配置信息,包括容器镜像、资源需求、重启策略、挂载卷、健康检查规则等),并按照PodSpec的要求执行容器的创建、启动、停止、重启等操作;二是健康检查,定期检查Pod和容器的健康状态,健康检查主要分为两种:容器探针(liveness probe、readiness probe、startup probe)和Pod状态检查。liveness probe用于检测容器是否正常运行,若检测失败,kubelet会根据Pod的重启策略重启容器;readiness probe用于检测容器是否准备就绪,若检测失败,会将该Pod从Service的EndpointSlice中移除,避免外部流量转发到未就绪的容器;startup probe用于检测容器是否启动完成,适用于启动时间较长的容器(如Java应用),避免因容器启动慢导致健康检查误判。
三是状态上报,kubelet会定期(默认每10秒)向kube-apiserver上报本节点的状态,包括节点的健康状态(Ready/NotReady)、资源使用情况(CPU、内存、磁盘使用率)、Pod的运行状态(Running/Pending/Failed/Terminating)等,让控制平面实时掌握每个工作节点的负载情况和运行状态,为kube-scheduler的调度决策提供依据,也为kube-controller-manager的状态维护提供支撑。四是资源管理,根据PodSpec中指定的资源需求,为容器分配CPU、内存等资源,通过Linux的cgroups技术实现资源隔离,确保每个容器的资源使用不会影响其他容器和节点本身,避免因某个容器过度占用资源导致节点过载。
此外,当工作节点出现故障(如网络中断、机器宕机)时,kubelet无法正常向控制平面上报状态,控制平面的Node控制器会在一定时间(默认5分钟)内检测到这一情况,将该节点标记为不可用(NotReady),并通知kube-scheduler将该节点上的Pod重新调度到其他健康节点,实现集群的自愈,确保业务不中断。
2. kube-proxy:集群网络代理,实现Pod间通信
kube-proxy是运行在每个工作节点上的网络代理组件,核心职责是“维护节点的网络规则,实现Pod之间、Pod与外部的通信”。在K8s集群中,每个Pod都有一个独立的IP地址,这个IP地址是集群内部的虚拟IP,仅能在集群内部访问,但Pod的生命周期是动态的——Pod会被创建、销毁、迁移,其IP地址也会随之变化,如何让Pod之间稳定通信,如何让外部流量能访问到集群内部的Pod,就是kube-proxy的核心作用。
kube-proxy主要通过两种方式实现网络转发,两种方式各有优势,适用于不同的集群规模,用户可以根据自身需求进行选择:
第一种是“iptables模式”,这是K8s默认的网络转发模式,适用于中小规模集群(节点数量在100个以内)。iptables是Linux系统中的防火墙工具,kube-proxy会通过修改节点的iptables规则,实现Service与Pod的端口映射和流量转发。具体来说,当用户创建一个Service时,kube-proxy会实时监听kube-apiserver中Service和EndpointSlice的变化,为该Service创建对应的iptables规则,将外部请求(或集群内部其他Pod的请求)转发到Service对应的Pod上。iptables模式的优点是部署简单、无需额外依赖,缺点是当集群规模较大(节点数量过多)时,iptables规则会变得非常复杂,导致流量转发延迟增加,影响集群的网络性能。
第二种是“IPVS模式”,适用于大规模集群(节点数量在100个以上),需要在节点上安装IPVS工具(如ipvsadm)。IPVS是Linux系统中的一种负载均衡技术,相比iptables,IPVS的性能更优,支持更多的连接数,能更好地应对大规模集群的流量转发需求。kube-proxy会通过IPVS创建虚拟服务器(VIP),将Service的IP地址作为VIP,然后将Service对应的Pod IP作为后端真实服务器,实现流量的负载分发。IPVS模式的优点是性能好、支持大规模集群,缺点是需要额外安装IPVS工具,部署和维护成本稍高。
无论是哪种模式,kube-proxy都会实时监听kube-apiserver中Service和EndpointSlice的变化,当Service的配置发生变化(如端口修改、Pod增减)时,kube-proxy会及时更新节点的网络规则(iptables规则或IPVS规则),确保流量能正确转发到目标Pod,避免因网络规则滞后导致的通信失败。此外,kube-proxy还支持会话保持、负载均衡算法(如轮询、最小连接数)等功能,进一步优化集群的网络通信性能。
3. 容器运行时(Container Runtime):容器运行环境
容器运行时是负责运行容器的软件,是K8s集群运行容器的基础,K8s通过容器运行时接口(CRI,Container Runtime Interface)与容器运行时交互,实现容器的生命周期管理——包括容器的创建、启动、停止、销毁、镜像拉取等操作。简单来说,容器运行时就是“容器的运行载体”,没有它,Pod和容器就无法在节点上运行。
K8s支持多种容器运行时,只要符合CRI规范,就能与K8s集群集成,常见的容器运行时包括以下几种:
Containerd:目前K8s的默认推荐容器运行时,是Docker公司开源的容器运行时,轻量、高效、稳定,专注于容器的运行和管理,去掉了Docker中不必要的功能(如Docker CLI、镜像构建),性能更优,资源占用更少,适合生产环境部署。
Docker:曾是最常用的容器运行时,也是很多开发者入门容器时接触的第一个工具,Docker不仅包含容器运行时(Docker Engine),还提供了镜像构建、容器管理、网络管理等一系列功能,功能强大、生态完善。但由于Docker的架构较为复杂,资源占用较多,且K8s在1.24版本后不再直接支持Docker(需要通过cri-dockerd适配器实现兼容),目前逐渐被Containerd替代。
CRI-O:专门为K8s设计的容器运行时,轻量、极简,完全遵循CRI规范,专注于与K8s的集成,避免了Docker中的冗余功能,适合对资源占用要求较高、追求极简部署的场景。
runc:一个轻量级的容器运行时,是Containerd、Docker等容器运行时的底层依赖,负责容器的创建和运行,实现了容器的隔离和资源限制,是容器运行时的核心组件。
容器运行时的核心作用是“解析容器镜像、创建容器进程、隔离容器资源”,具体工作流程如下:当kubelet收到创建Pod的指令后,会通过CRI向容器运行时发送请求,请求中包含Pod的配置信息(如容器镜像地址、资源需求、挂载卷等);容器运行时收到请求后,会先从镜像仓库(如Docker Hub、私有镜像仓库)拉取对应的容器镜像,镜像拉取完成后,会解析镜像,创建容器进程,并通过Linux的namespace技术实现容器的网络隔离、进程隔离,通过cgroups技术实现容器的资源限制(如CPU、内存配额);容器启动后,容器运行时会实时监控容器的运行状态,并将状态反馈给kubelet,确保容器按预期运行。
四、K8s集群工作流程
了解了控制平面和工作节点的核心组件后,我们通过一个“创建Pod并运行”的完整流程,结合每个组件的作用,详细拆解K8s集群的“指挥-执行”全链路,帮你串联起整个架构的逻辑,真正理解各个组件如何协同工作:
用户操作发起请求:用户通过kubectl命令(如kubectl create pod nginx --image=nginx),或通过API接口(如Postman调用K8s API),向kube-apiserver发送“创建Pod”的请求,请求中包含Pod的完整配置信息,如容器镜像地址、CPU/内存资源需求、重启策略、挂载卷、健康检查规则等。
请求验证与数据存储:kube-apiserver收到请求后,首先对请求进行合法性校验,包括验证用户是否有创建Pod的权限(通过RBAC权限控制)、Pod的配置格式是否正确、资源需求是否合理(如是否超过集群的可用资源);校验通过后,kube-apiserver会将Pod的配置信息写入etcd中进行持久化存储,此时Pod的状态被标记为Pending(等待调度),并向用户返回请求成功的响应。
调度决策:kube-scheduler实时监听kube-apiserver,当发现有状态为Pending的Pod时,会从etcd中读取该Pod的配置信息和集群的节点状态信息,执行调度逻辑——先通过过滤规则(如资源需求、节点亲和性)筛选出可用节点,再通过打分规则对可用节点进行打分,选择得分最高的节点作为目标运行节点;调度决策完成后,kube-scheduler会将调度结果(Pod与目标节点的关联关系)通过kube-apiserver写入etcd中。
容器创建与启动:目标工作节点上的kubelet实时监听kube-apiserver,当发现有调度到本节点的Pod时,会从etcd中读取该Pod的配置信息,然后通过CRI调用容器运行时,执行容器创建操作;容器运行时收到请求后,从指定的镜像仓库拉取对应的容器镜像,镜像拉取完成后,创建容器进程,配置容器的网络、挂载卷等,启动容器;容器启动完成后,容器运行时将容器的运行状态反馈给kubelet。
状态上报与同步:kubelet定期检查Pod和容器的健康状态,将Pod的状态(如Running)、容器的状态(如Running)、节点的资源使用情况等信息,通过kube-apiserver上报给etcd,实现集群状态的同步;此时,用户通过kubectl get pods命令,就能看到该Pod的状态为Running,表示Pod已正常运行。
网络规则配置:kube-proxy实时监听kube-apiserver中Service和EndpointSlice的变化,当该Pod对应的Service(若已创建)的EndpointSlice更新后,kube-proxy会及时更新本节点的网络规则(iptables或IPVS规则),确保外部流量(或集群内部其他Pod的请求)能正确转发到该Pod,实现Pod的可访问性。
异常处理与自愈:若Pod中的容器出现异常(如进程崩溃),kubelet会通过健康检查检测到异常,根据Pod的重启策略(如Always、OnFailure)重启容器;若工作节点出现故障(如网络中断、机器宕机),kubelet无法正常上报状态,控制平面的Node控制器会检测到节点异常,将该节点标记为不可用,kube-scheduler会将该节点上的所有Pod重新调度到其他健康节点,确保业务不中断;若Pod的实际副本数少于期望副本数,副本控制器会自动创建新的Pod,维持副本数稳定。
五、架构设计亮点
K8s的架构设计之所以能成为容器编排的事实标准,核心在于其优秀的设计理念,主要有以下4个亮点,也是它能适配不同规模、不同场景的关键:
解耦设计:控制平面与工作节点分离,控制平面负责决策和管理,工作节点负责执行和运行,两者通过API通信,降低了组件之间的耦合度;同时,控制平面内部的各个组件(kube-apiserver、etcd、kube-scheduler、kube-controller-manager)也各司其职、相互独立,便于组件的单独扩展、升级和维护,比如可以单独升级kube-scheduler,而不影响其他组件的运行。
高可用设计:核心组件均支持多实例部署,避免单点故障——kube-apiserver可部署多个实例,配合负载均衡器实现高可用;etcd部署3个或5个节点,通过Raft算法实现高可用;kube-scheduler和kube-controller-manager也可部署多个实例,通过选举机制确保只有一个实例在工作,其他实例作为备用,一旦主实例故障,备用实例会自动接管工作,确保控制平面的稳定运行;工作节点部署多个,通过冗余实现业务的高可用。
自愈能力:通过kube-controller-manager的控制循环、kubelet的健康检查,实现集群的自动自愈——无需人工干预,就能自动修复Pod异常、节点故障、副本数不足等问题,大幅降低集群的维护成本,提升业务的连续性;比如Pod崩溃后自动重启,节点故障后Pod自动迁移,确保业务不中断。
可扩展设计:K8s提供了丰富的扩展接口,支持自定义调度策略、自定义控制器、自定义容器运行时、自定义网络插件(如Calico、Flannel)等,开发者可以根据自身的业务需求,扩展K8s的功能,适配不同的业务场景——无论是GPU密集型、高IO、低延迟等特殊业务,还是大规模集群、轻量化部署等不同规模场景,都能通过扩展实现适配。