K8s (Kubernetes) 架构详解:构建云原生基石
引言
在当今快速发展的技术浪潮中,云计算、微服务和持续交付已成为企业提升效率、加速创新的重要驱动力。而支撑这一切的底层技术之一,便是容器化。随着容器技术的普及,如何有效管理、自动化部署、扩展和操作大量容器化应用成为了新的挑战。正是在这样的背景下,Kubernetes (简称 K8s) 应运而生,并迅速崛起成为容器编排领域的领导者和事实标准。
Kubernetes 是一个开源的容器编排平台,它自动化了容器化应用程序的部署、扩展和管理。它提供了一个健壮、可扩展、高可用的系统,能够处理复杂的应用生命周期。然而,要充分发挥 Kubernetes 的强大能力,并解决在使用过程中遇到的各种问题,深入理解其底层架构至关重要。Kubernetes 架构的设计精妙,体现了声明式 API、控制循环 (Control Loop)、组件解耦以及高可用性等核心理念。理解这些理念及其在各组件中的具体实现,是掌握云原生应用部署和管理的关键。
本文将对 Kubernetes 的核心架构进行详细剖析,从宏观的两大组成部分——控制平面 (Control Plane) 和工作节点 (Worker Node)——出发,逐步深入到各个关键组件的功能、职责及其相互之间的协作方式,揭示 Kubernetes 如何构建云原生应用的坚实基石。
第一部分:Kubernetes 高层架构概览
Kubernetes 集群由两类主要节点组成:
- 控制平面 (Control Plane 或 Master Node): 这是集群的“大脑”。它负责维护集群的期望状态(即用户希望应用运行的样子)、调度应用程序、响应集群事件(如节点故障)、执行更新等管理任务。控制平面通常包含多个相互协作的组件,并且为了高可用性,生产环境中通常会部署多个控制平面节点。
- 工作节点 (Worker Node): 这是集群的“体力”。它们负责运行实际的应用容器。每个工作节点上都运行着接收控制平面指令的代理程序,以及用于运行容器的运行时环境。工作节点上的代理程序会向控制平面汇报节点的状态,并接收其指派的任务(运行 Pod)。
用户或自动化系统通过与控制平面交互来管理集群。这种交互通常通过 Kubernetes API 进行。用户告诉控制平面他们想要的最终状态(例如,“我想要运行 3 个 Nginx 的副本”),控制平面则负责将集群的当前状态驱动到期望状态。
第二部分:控制平面 (Control Plane) 核心组件详解
控制平面是 Kubernetes 集群的大脑,它负责整个集群的运作和管理。它由一系列相互协作的组件组成。
2.1 etcd:集群状态存储
- 作用: etcd 是一个分布式、高可用的强一致性键值存储系统。它是 Kubernetes 集群所有数据(集群状态、配置信息、元数据等)的唯一持久化存储后端。可以形象地将 etcd 比作 Kubernetes 的“记忆”或“数据库”。
- 重要性: etcd 的可用性和一致性对于整个 Kubernetes 集群至关重要。如果 etcd 出现故障或数据不一致,整个集群将无法正常工作。因此,生产环境中的 etcd 通常会部署成一个多实例的集群,以确保高可用性和数据可靠性(通过 Raft 一致性算法)。
- 交互方式: etcd 只与 kube-apiserver 直接通信。其他控制平面组件和工作节点不会直接读写 etcd,所有对集群状态的改变都必须通过 kube-apiserver 进行。
2.2 kube-apiserver:API 服务
- 作用: kube-apiserver 是 Kubernetes 控制平面的核心,它是所有外部请求(来自用户、CLI 工具如 kubectl、或者其他集群组件)的唯一入口点。它负责暴露 Kubernetes API,处理 RESTful 请求,进行身份验证 (Authentication)、授权 (Authorization) 和准入控制 (Admission Control)。
- 核心功能:
- API 暴露: 提供统一的 RESTful API 接口,供用户和内部组件交互。
- 请求处理: 接收、校验和处理所有对集群对象的创建、读取、更新和删除 (CRUD) 请求。
- 身份验证和授权: 确保只有合法的用户或服务账户能够访问 API,并根据 RBAC (Role-Based Access Control) 等策略决定其权限。
- 准入控制: 在对象持久化到 etcd 之前,通过一系列准入控制器对请求进行拦截和修改,执行安全策略、资源限制等。这是非常重要的安全和策略执行层。
- 状态持久化: 将经过处理和校验的对象状态持久化到 etcd 中。
- Watch 机制: 提供 watch API,允许其他组件监听 etcd 中对象的变更事件,这是实现控制循环的基础。
- 重要性: kube-apiserver 是集群的“前端”,是所有操作的必经之路。它的高性能和高可用性直接影响到整个集群的响应能力和稳定性。为了高可用,通常会部署多个 kube-apiserver 实例,并通过负载均衡器对外提供服务。
2.3 kube-scheduler:调度器
- 作用: kube-scheduler 负责监听 kube-apiserver 中新创建的、但尚未分配到节点 (Node) 的 Pod。它根据预定的调度策略(例如资源需求、节点可用性、亲和性/反亲和性、污点/容忍度等),为这些 Pod 选择一个最合适的节点来运行。
- 工作流程:
- 监听 kube-apiserver,获取未调度的 Pod。
- 执行过滤 (Filtering) 过程:根据 Pod 的资源需求、节点限制等,从所有节点中筛选出符合条件的节点列表。
- 执行打分 (Scoring) 过程:根据各种调度策略(如资源利用率、Pod 反亲和性等),为每个符合条件的节点计算一个分数。
- 选择分数最高的节点作为 Pod 的目标节点。
- 通过 kube-apiserver 将 Pod 绑定 (Bind) 到选定的节点上,更新 Pod 对象的状态。
- 重要性: 调度器的效率和策略直接影响到集群资源的利用率和应用的可用性。良好的调度策略可以确保工作负载均衡分布,避免某些节点过载,并满足应用对拓扑结构的要求。
2.4 kube-controller-manager:控制器管理器
- 作用: kube-controller-manager 包含了一系列控制器 (Controller),这些控制器通过 kube-apiserver 监听集群中的资源对象(如 Pod、Deployment、Service、Node 等)的状态变化,并将集群的当前状态驱动到期望状态。这是 Kubernetes 实现“自我修复”和自动化管理的核心。
- 控制器模式 (Control Loop): 每个控制器都遵循类似的模式:
- 通过 kube-apiserver 观察 (Observe) 集群的当前状态。
- 比较 (Diff) 当前状态与资源对象的期望状态。
- 如果当前状态与期望状态不符,则通过 kube-apiserver 行动 (Act),创建、更新或删除资源对象,以驱动集群向期望状态靠拢。
- 主要内置控制器: kube-controller-manager 集成并运行着多种控制器,例如:
- Node Controller: 监听节点状态,如果节点长时间不可达,则将其标记为 unhealthy,并在必要时触发其上 Pod 的重新调度。
- Replication Controller / ReplicaSet Controller: 确保特定 Pod 的副本数量始终与期望值 (replicas) 相符。如果 Pod 数量少于期望值,则创建新 Pod;如果多于,则终止多余的 Pod。
- Deployment Controller: 管理 ReplicaSet 的创建和更新,提供声明式更新(如滚动更新、回滚)的能力。
- StatefulSet Controller: 管理有状态应用(如数据库)的 Pod,提供稳定的网络标识符、持久化存储和有序的部署/缩放/删除。
- Service Controller: 监听 Service 对象,并与云提供商的负载均衡器集成(如果在云环境中),为其创建相应的外部负载均衡器。
- Endpoint Controller: 监听 Service 和 Pod 的变化,维护 Service 对应的 Endpoint 列表(即 Service 流量应该被转发到的 Pod IP 和端口列表)。
- Job Controller: 运行一次性或周期性任务。
- Namespace Controller: 管理 Namespace 的生命周期。
- ServiceAccount Controller: 为每个 Namespace 创建默认的 ServiceAccount。
- 等等…
- 重要性: 控制器管理器是 Kubernetes 实现自动化运维和弹性伸缩的关键。通过不断地协调和校正,它保证了集群的韧性,即使发生故障或配置漂移,系统也能自动恢复到期望状态。
2.5 cloud-controller-manager (可选)
- 作用: cloud-controller-manager 是 Kubernetes 1.6 版本引入的组件,用于将 Kubernetes 集群与特定的云平台(如 AWS, GCP, Azure 等)集成。它将一些依赖于云平台的控制器从 kube-controller-manager 中分离出来。
- 主要控制器 (云平台相关):
- Node Controller: 检查云平台 API 确定节点是否已经被删除。
- Route Controller: 在云平台中配置路由,使容器网络能够跨节点通信。
- Service Controller: 在云平台中创建、更新和删除负载均衡器。
- Volume Controller: 与云平台的存储服务集成,管理持久卷 (PersistentVolume) 的生命周期。
- 重要性: 将云平台相关的逻辑从核心控制器中解耦,使得 Kubernetes 核心更加独立和可移植,同时允许云提供商根据自身特性实现更紧密的集成。如果你的集群运行在裸金属环境或不使用特定的云服务,则不需要这个组件。
第三部分:工作节点 (Worker Node) 核心组件详解
工作节点是 Kubernetes 集群的执行者,它们负责运行由控制平面调度的 Pod。每个工作节点都运行着以下关键组件:
3.1 Kubelet
- 作用: Kubelet 是运行在每个工作节点上的主要代理程序。它负责与控制平面通信,接收 Pod 的定义 (PodSpec),并确保 Pod 中描述的容器在节点上按照期望的状态运行。
- 核心功能:
- 与 API Server 通信: 通过 watch 机制监听分配给该节点的 Pod 列表。
- 管理 Pod 和容器: 根据接收到的 PodSpec,指示容器运行时创建、启动、停止和删除容器。
- 报告节点和 Pod 状态: 向 kube-apiserver 报告节点自身的资源信息(CPU、内存、磁盘等)、健康状况以及在该节点上运行的 Pod 和容器的状态。
- 容器和卷管理: 负责挂载 Pod 所需的存储卷,并将其暴露给容器。
- 容器存活探针 (Liveness Probe) 和就绪探针 (Readiness Probe): 根据 Pod 定义中配置的探针,定期检查容器的健康状况和是否准备好接收流量,并向 kube-apiserver 报告结果。
- 资源监控: 通过 cAdvisor(或者集成到容器运行时中)监控节点和容器的资源使用情况。
- 重要性: Kubelet 是工作节点上的“管家”,它是控制平面与工作节点上实际工作负载之间的桥梁。它的稳定运行是 Pod 正常运行的基础。
3.2 Kube-proxy
- 作用: Kube-proxy 是运行在每个工作节点上的网络代理。它负责为 Kubernetes 中的 Service 提供网络功能,主要通过维护节点上的网络规则(iptables, IPVS 等)来实现 Service 的虚拟 IP 和负载均衡。
- 工作原理:
- 监听 kube-apiserver,获取 Service 和 Endpoint 对象的变化。
- 根据 Service 的定义和对应的 Endpoint 列表,在节点上创建相应的网络规则。
- 当有流量访问 Service 的 Cluster IP (VIP) 时,这些网络规则会将流量负载均衡地转发到该 Service 对应的 Pod IP 和端口上。
- 代理模式 (Proxy Mode): Kube-proxy 支持多种工作模式,常见的是:
- iptables: 使用 Linux 内核的 iptables 规则。它是默认模式,性能良好,但在服务和 Pod 数量巨大时规则链会很长,管理开销增加。
- IPVS: 使用 Linux 内核的 IPVS (IP Virtual Server)。在大规模集群中通常性能优于 iptables,支持更多负载均衡算法。
- Userspace (已废弃/不推荐): 早期的模式,性能较差。
- 重要性: Kube-proxy 是实现 Kubernetes Service 抽象的关键组件,它使得应用无需关心 Pod 的具体 IP 地址变化,只需通过稳定的 Service 名称或 IP 即可访问后端 Pod,极大地简化了服务发现和负载均衡。
3.3 Container Runtime
- 作用: 容器运行时是负责运行容器的软件。它是 Kubelet 的下层依赖,负责拉取容器镜像、创建和管理容器进程、分配资源(如 CPU、内存、存储)给容器等。
- 容器运行时接口 (CRI – Container Runtime Interface): 为了支持不同的容器运行时,Kubernetes 定义了 CRI 接口。Kubelet 通过 CRI 与容器运行时交互,而无需关心具体的运行时实现细节。这使得 Kubernetes 可以轻松地支持多种容器运行时。
- 常见的容器运行时:
- Docker Engine (通过 dockershim 或 cri-dockerd): 曾经最流行的运行时,但 dockershim 已在 Kubernetes 1.24 中移除,需要使用 cri-dockerd 转接。
- containerd: 一个工业标准的容器运行时,由 Docker 公司贡献给 CNCLinux 基金会。许多 Kubernetes 发行版默认使用 containerd。
- CRI-O: 专门为 Kubernetes 设计的轻量级容器运行时,专注于支持 CRI 接口。
- 重要性: 容器运行时是 Pod 中容器的实际执行者。它的稳定性、性能和安全性直接影响到应用容器的运行效果。
第四部分:Kubernetes 组件之间的协作与交互流程
理解各个组件的功能只是第一步,更重要的是理解它们如何协同工作来响应用户的请求和维护集群状态。以下是一些典型的交互流程示例:
-
创建 Pod 的流程:
- 用户或控制器(如 Deployment)通过
kubectl apply -f pod.yaml
或其他方式向 kube-apiserver 发送创建 Pod 的请求。 - kube-apiserver 接收请求,进行身份验证、授权和准入控制。
- 如果请求合法且通过准入控制,kube-apiserver 将 Pod 对象的状态写入 etcd。
- kube-scheduler 通过 watch 机制发现 etcd 中有一个新的、未调度的 Pod。
- kube-scheduler 执行调度算法,为 Pod 选择一个合适的节点。
- kube-scheduler 通过 kube-apiserver 更新 Pod 对象,将其
.spec.nodeName
字段设置为选定的节点名称(这称为绑定 Pod 到节点)。 - 目标节点上的 kubelet 通过 watch 机制发现有一个新的 Pod 被分配给了它。
- kubelet 根据 PodSpec,指示节点上的容器运行时拉取所需的容器镜像。
- 容器运行时创建并启动 Pod 中的容器。
- kubelet 持续监控 Pod 和容器的状态,并通过 kube-apiserver 报告给控制平面。
- 用户或控制器(如 Deployment)通过
-
创建 Service 的流程:
- 用户通过 kube-apiserver 创建 Service 对象。
- kube-apiserver 将 Service 对象写入 etcd。
- Service Controller 通过 watch 机制发现新的 Service。如果在云环境中,它可能会调用云平台的 API 创建负载均衡器。
- Endpoint Controller 通过 watch 机制发现新的 Service 以及符合该 Service 选择器 (selector) 的 Pods。它创建一个或更新一个 Endpoint 对象,其中包含符合条件的 Pod 的 IP 地址和端口列表。
- kube-apiserver 将 Endpoint 对象写入 etcd。
- 每个工作节点上的 kube-proxy 通过 watch 机制发现新的 Service 和 Endpoint 对象。
- kube-proxy 根据 Service 和 Endpoint 的信息,在节点上配置 iptables 或 IPVS 规则。这些规则将 Service 的 Cluster IP 流量转发到 Endpoint 中列出的 Pods 上。
-
节点故障的恢复:
- 某个工作节点发生故障(例如,断电、网络分区)。
- 该节点上的 kubelet 停止向 kube-apiserver 发送心跳。
- Node Controller 通过 watch 机制发现该节点长时间没有更新状态(通常有超时设置,如 5 分钟)。
- Node Controller 将该节点标记为
NodeReady=false
,并在一定宽限期后(通常是 5-10 分钟,取决于 Pod 的terminationGracePeriodSeconds
和podEvictionTimeout
设置)将该节点标记为不可调度。 - Node Controller(或独立的 Eviction Controller)开始逐出 (Evict) 该节点上的 Pods。对于由 Deployment 等控制器管理的 Pods,这将意味着删除这些 Pods 的对象。
- ReplicaSet 或 Deployment 控制器通过 watch 机制发现其管理的 Pod 数量减少了(因为旧的 Pod 被删除了)。
- ReplicaSet 或 Deployment 控制器创建新的 Pod 对象,以满足期望的副本数量。
- 新创建的 Pod 被标记为未调度。
- kube-scheduler 发现这些新的未调度 Pods,并在健康的节点上为其选择运行位置。
- 健康的节点上的 Kubelet 接收到这些新的 Pod,并启动它们。集群恢复到期望状态。
第五部分:其他重要概念及其与架构的关系
- 声明式 API 和期望状态: Kubernetes 的核心是声明式 API。用户不是告诉系统“执行这个步骤”,而是告诉系统“我想要达到这个状态”。控制平面及其控制器通过不断地调整当前状态来匹配这个期望状态。这是 Kubernetes 强大自动化能力的基础,也是其架构设计的核心驱动力。所有组件都围绕着 API Server 和 etcd 中的状态进行协作。
- 控制循环 (Control Loop): 这是控制器模式的精髓,也是 Kubernetes 自动化和韧性的基石。每个控制器都在一个无限循环中运行,不断地观察、比较、行动,直到达到期望状态。这种模式使得系统对外部变化(如节点故障、用户请求)具有很强的适应性。
- 对象的抽象: Kubernetes 抽象了各种应用和基础设施资源为 API 对象(如 Pod, Service, Deployment, Volume, Namespace 等)。用户通过操作这些对象来与集群交互。这种面向对象的设计使得系统易于理解和扩展。
- 插件机制和扩展性: Kubernetes 提供了丰富的插件接口,如 CRI (Container Runtime Interface), CNI (Container Network Interface), CSI (Container Storage Interface), Admission Controllers, Scheduler Extenders 等。这些接口允许用户或第三方厂商插入自己的实现,极大地增强了 Kubernetes 的灵活性和可扩展性。Custom Resource Definitions (CRDs) 和 Operators 更是将这种扩展能力提升到了新的高度,允许用户定义自己的资源类型和自动化管理逻辑,构建更高级别的抽象。这使得 Kubernetes 能够成为云原生生态系统的“基石”,被各种中间件、服务网格、监控系统等集成和扩展。
第六部分:架构的 Scalability 和 High Availability
Kubernetes 架构在设计时就考虑了可扩展性和高可用性:
- 控制平面高可用:
- kube-apiserver:可以运行多个实例,通过外部负载均衡器分发请求。
- etcd:通常部署为奇数个(3、5、7)节点的集群,利用 Raft 协议保证数据一致性和高可用性。需要集群中多数节点存活才能正常工作(Quorum)。
- kube-controller-manager 和 kube-scheduler:可以运行多个实例,但通常只有一个处于领导者 (Leader) 状态,通过租约机制 (Lease) 选举产生,确保不会重复执行任务。
- 工作节点 Scalability: 通过简单地增加或减少工作节点来扩展集群的处理能力。Kubelet 会自动注册到控制平面,并开始接收任务。
- 负载均衡: kube-proxy 和 Service 对象提供了内置的负载均衡能力。
- 水平 Pod 自动伸缩 (HPA): Horizontal Pod Autoscaler 是一个内置的控制器,可以根据 CPU 利用率、内存或其他自定义指标自动调整 Deployment 或 ReplicaSet 中的 Pod 副本数量。
- 集群自动伸缩 (Cluster Autoscaler): 根据待调度的 Pod 数量和节点资源使用情况,自动增加或减少集群中的工作节点数量(通常在云环境中与云提供商的 API 集成)。
结论
Kubernetes 的架构是一个精心设计的分布式系统,其核心理念是通过声明式 API 和控制循环模式,持续地将集群的当前状态驱动到用户期望的状态。控制平面作为大脑,负责决策、调度和协调;工作节点作为执行者,负责运行实际的工作负载。各组件之间通过 API Server 和 etcd 进行交互,高度解耦,并通过强大的插件机制提供了出色的可扩展性。
理解 Kubernetes 的架构不仅仅是了解各个组件的名称和作用,更重要的是理解它们之间的协作方式、控制循环的模式以及如何共同实现声明式管理和自动化。正是这种架构,使得 Kubernetes 能够有效地管理大规模容器化应用,应对复杂的运维挑战,并成为构建和运行现代云原生应用的强大基石。掌握 Kubernetes 架构的深层原理,将使您能够更有效地设计、部署、排查和优化您的云原生应用,充分利用 Kubernetes 的潜力。随着技术的不断演进,Kubernetes 架构自身也在不断发展和完善,但其核心理念和组件功能将长期保持其重要性。