K8S原理刨析
一、K8S 架构探秘
Kubernetes 采用主从分布式架构,一个 K8S 集群主要由主节点(Master 节点)和工作节点(Node 节点)组成。主节点就像是整个集群的 “大脑”,负责管理和控制整个集群的状态和行为;而工作节点则如同 “四肢”,承担着实际运行应用程序的任务。下面我们通过一张架构图来直观地认识一下 K8S 集群的架构。
1.1 主从分布式架构
在 K8S 集群中,主节点和工作节点相互协作,共同完成容器化应用的部署、管理和扩展。主节点负责集群的全局管理和调度,而工作节点则专注于运行容器化应用,它们之间通过可靠的网络通信进行信息交互和指令传递。这种主从分布式架构使得 K8S 集群具有良好的扩展性和高可用性,可以轻松应对大规模容器化应用的管理需求。例如,当业务量增加时,可以方便地向集群中添加新的工作节点,以扩展集群的计算能力;当某个工作节点出现故障时,主节点能够及时感知并将该节点上的工作负载转移到其他健康节点上,确保应用的持续运行。
1.2 控制平面组件
主节点上运行着控制平面组件,这些组件是 Kubernetes 集群的核心控制单元,负责管理集群的状态、资源分配和任务调度等关键功能。下面我们来详细了解一下控制平面的各个组件。
(1)API Server
API Server 是 Kubernetes 集群的入口,就像一个 “门卫”,接收来自客户端(如 kubectl 命令行工具、Kubernetes Dashboard 等)的请求,并提供 REST API 供外部系统与集群进行交互。它是所有集群操作的唯一入口,负责认证、授权、准入控制和数据校验等重要功能,确保只有合法的请求才能进入集群并对资源进行操作。例如,当我们使用 kubectl 命令创建一个新的 Pod 时,这个请求首先会被发送到 API Server。API Server 会对请求进行身份验证,检查我们是否有权限执行该操作,然后对请求中的数据进行校验,确保数据格式和内容符合 Kubernetes 的规范。如果请求通过了所有检查,API Server 才会将请求转发给相应的控制器进行后续处理。
(2)Controller Manager
Controller Manager 是一个包含多个控制器的集合,它的主要职责是通过不断地监测集群的实际状态,并与用户定义的期望状态进行对比,确保集群始终处于期望的运行状态。一旦发现实际状态与期望状态存在差异,Controller Manager 会自动采取相应的措施来调整集群,使其恢复到期望状态。例如,Deployment Controller 负责管理无状态应用的部署,它会确保 Pod 的副本数量始终符合用户在 Deployment 配置中设定的数量。如果当前运行的 Pod 副本数量少于期望数量,Deployment Controller 会自动创建新的 Pod;反之,如果副本数量过多,它会删除多余的 Pod。常见的控制器及其功能如下:
- ReplicaSet Controller:负责维护指定数量的 Pod 副本,通过标签选择器来管理 Pod 集合,确保集群中实际运行的 Pod 副本数量与用户定义的副本数量一致。
- Node Controller:监控节点的状态,处理节点的加入、离开和故障等事件。当发现某个节点失联时,Node Controller 会尝试重新连接该节点,如果多次尝试失败,它会将该节点标记为不可用,并将该节点上的 Pod 重新调度到其他健康节点上。
- Job Controller:用于管理一次性任务,确保任务能够成功完成。它会创建 Pod 来执行任务,并在任务完成或失败后对 Pod 进行相应的清理操作。
- DaemonSet Controller:确保每个节点上都运行一个指定的 Pod 副本,常用于部署系统级别的守护进程,如日志收集代理、监控代理等。
(3)Scheduler
Scheduler 就像是一个 “调度员”,负责根据一系列的调度策略和算法,将 Pod 分配到集群中最合适的 Node 节点上运行。在调度过程中,Scheduler 主要分为两个阶段:过滤和打分。首先,它会根据 Pod 的资源需求、节点的资源状况、节点的标签以及其他一些约束条件,过滤掉不符合要求的节点,筛选出一组候选节点。例如,如果一个 Pod 需要大量的 CPU 资源,Scheduler 会过滤掉那些 CPU 资源不足的节点。然后,Scheduler 会对这些候选节点进行打分,根据预先定义的优先级函数,综合考虑各种因素,如节点的资源利用率、节点与其他相关 Pod 的亲和性或反亲和性等,为每个候选节点计算一个得分。最后,Scheduler 会选择得分最高的节点,将 Pod 绑定到该节点上进行部署。通过这种过滤和打分机制,Scheduler 能够实现资源的有效分配和利用,提高集群的整体性能和效率。
(4)etcd
etcd 是一个分布式键值存储系统,就像集群的 “记忆仓库”,用于保存 Kubernetes 集群的所有配置数据和状态信息,包括集群中所有资源对象(如 Pod、Service、Deployment 等)的定义和状态。etcd 具有高可用性和强一致性的特点,它通过 Raft 协议实现数据的复制和一致性维护,确保在集群中的多个 etcd 实例之间数据能够保持一致。即使部分 etcd 实例出现故障,整个集群仍然能够正常工作,并且数据不会丢失或损坏。例如,当我们创建一个新的 Service 时,API Server 会将这个 Service 的定义信息存储到 etcd 中。当其他组件需要获取这个 Service 的信息时,它们可以从 etcd 中读取到最新的、一致的数据。etcd 的数据持久性和一致性对于 Kubernetes 集群的稳定运行至关重要,它是整个集群状态的可靠来源。
1.3 工作节点组件
工作节点上运行着一系列组件,这些组件负责与主节点进行通信,接收并执行主节点下达的任务,确保容器化应用在节点上的正常运行和网络通信。下面我们来详细了解一下工作节点上的各个组件。
(1)Kubelet
Kubelet 是运行在每个工作节点上的主要代理组件,它就像是节点的 “管家”,负责管理本节点上的 Pod 和容器。Kubelet 与 API Server 保持密切通信,定期从 API Server 获取分配到本节点的 Pod 清单,并确保这些 Pod 中的容器按照预期状态运行。如果发现某个 Pod 的状态异常,Kubelet 会尝试进行修复,比如重新启动容器。同时,Kubelet 还负责向 API Server 报告节点和 Pod 的状态信息,包括节点的资源使用情况、Pod 的运行状态、容器的健康状况等。例如,当主节点的 Scheduler 将一个 Pod 调度到某个工作节点后,Kubelet 会根据 Pod 的定义信息,调用容器运行时(如 Docker 或 containerd)来创建和启动容器,并为容器配置网络和存储等资源。在容器运行过程中,Kubelet 会持续监控容器的运行状态,一旦发现容器出现故障,它会及时采取措施进行处理,并将相关信息反馈给 API Server。
(2)Kube - proxy
Kube - proxy 是工作节点上的网络代理组件,它主要负责维护节点上的网络规则,实现 Service 与 Pod 之间的网络转发和负载均衡功能。每个 Service 在 Kubernetes 集群中都有一个虚拟的 IP 地址,当客户端向 Service 的 IP 地址发送请求时,Kube - proxy 会根据预先配置的网络规则,将请求转发到后端对应的 Pod 上。同时,Kube - proxy 还支持多种负载均衡算法,如轮询、随机等,能够根据实际需求将流量均匀地分配到各个 Pod 上,从而实现服务的高可用性和高性能。例如,当一个 Service 后端有多个 Pod 时,Kube - proxy 会根据负载均衡算法选择其中一个 Pod 来处理客户端的请求,确保每个 Pod 都能合理地分担负载,避免某个 Pod 因负载过高而出现性能瓶颈。
(3)容器运行时
容器运行时是负责在节点上运行容器的组件,它就像是容器的 “孵化器”,提供了创建、启动和停止容器的功能。在 Kubernetes 中,常见的容器运行时包括 Docker 和 containerd 等。以 Docker 为例,它是一个开源的容器引擎,通过利用 Linux 内核的 cgroups 和 namespaces 等技术,实现了容器的隔离和资源限制。Docker 可以将应用程序及其依赖项打包成一个镜像,然后在任何支持 Docker 的环境中运行这个镜像,具有良好的可移植性和便捷性。Containerd 则是一个工业级标准的容器运行时,它强调简单性、健壮性和可移植性,负责管理容器的生命周期、镜像的传输和存储、网络和存储的配置等核心功能。与 Docker 相比,containerd 更加轻量级,调用链更短,组件更少,在 Kubernetes 集群中得到了越来越广泛的应用。例如,当 Kubelet 需要在节点上创建一个新的容器时,它会调用容器运行时(如 Docker 或 containerd)的 API 来完成容器的创建和启动操作,容器运行时会根据容器镜像的定义,在节点上创建一个隔离的容器环境,并启动容器中的应用程序。
二、K8S 工作流程深度剖析
了解了 K8S 的架构后,我们接下来深入探讨 K8S 的工作流程,看看各个组件是如何协同工作,实现容器化应用的部署和管理的。以创建一个简单的 Pod 为例,其工作流程主要包含以下几个关键步骤:
3.1 用户提交请求
用户通过 kubectl 命令行工具、Kubernetes Dashboard 或其他客户端,编写并提交包含 Pod 定义的 YAML 或 JSON 文件,向 API Server 发送创建 Pod 的请求。这些文件中详细定义了 Pod 的各种属性,如使用的容器镜像、资源需求、环境变量等。例如,下面是一个简单的 Pod 定义文件:
apiVersion: v1
kind: Pod
metadata:name: my-pod
spec:containers:- name: my-containerimage: nginx:latestports:- containerPort: 80
在这个文件中,我们定义了一个名为 my-pod 的 Pod,它包含一个使用 nginx:latest 镜像的容器,并且容器暴露 80 端口。用户使用kubectl apply -f pod.yaml命令将这个请求发送给 API Server。
3.2 API Server 与 etcd 协作
API Server 接收到请求后,首先对请求进行认证和授权,确保请求来自合法用户且具有相应的权限。然后,API Server 对请求中的数据进行严格校验,检查数据格式是否符合 Kubernetes 的 API 规范,字段是否正确等。如果请求通过了所有验证,API Server 会将 Pod 的期望状态(即用户定义的 Pod 配置信息)存储到 etcd 中。etcd 就像一个可靠的 “保险箱”,将这些关键信息持久化保存,为整个集群提供稳定的数据支持。
3.3 调度器工作
Scheduler 时刻监控着 etcd 中未被调度的 Pod 信息。当它发现有新的 Pod 需要调度时,便开始工作。Scheduler 首先根据一系列的过滤规则,排除那些不符合条件的 Node 节点。这些规则包括节点的资源状况(如 CPU、内存是否满足 Pod 的需求)、节点的标签(是否与 Pod 的亲和性或反亲和性规则匹配)以及其他一些约束条件。例如,如果一个 Pod 需要大量的 CPU 资源,而某个节点的 CPU 已经处于高负载状态,那么这个节点就会被过滤掉。在筛选出候选节点后,Scheduler 会根据预先定义的优先级函数对这些候选节点进行打分,综合考虑各种因素,如节点的资源利用率、节点与其他相关 Pod 的亲和性或反亲和性等。最后,Scheduler 选择得分最高的节点,将 Pod 绑定到该节点上,并将绑定信息更新到 etcd 中。
3.4 节点执行
在目标节点上,Kubelet 持续监听着 API Server 的指令,当它发现有分配到本节点的 Pod 时,便开始执行一系列操作。Kubelet 首先会检查节点上是否已经存在 Pod 定义中所需的容器镜像,如果镜像不存在,Kubelet 会根据镜像地址从镜像仓库中下载镜像。下载完成后,Kubelet 调用容器运行时(如 Docker 或 containerd),根据 Pod 的定义创建并启动容器。同时,Kubelet 会为容器配置网络和存储等资源,确保容器能够正常运行。在容器运行过程中,Kubelet 会持续监控容器的状态,定期向 API Server 报告容器的运行情况,包括容器是否正常运行、资源使用情况等。如果发现容器出现故障,Kubelet 会尝试进行修复,比如重新启动容器。
3.5 服务发现与负载均衡
当 Pod 创建完成并运行后,如果该 Pod 需要被其他服务访问,就需要通过 Service 来暴露。Kube - proxy 负责实现 Service 的网络代理和负载均衡功能。Kube - proxy 监听 API Server 中 Service 和 Endpoint 的变化情况,当它发现有新的 Service 创建或者 Endpoint 发生变化时,会及时更新节点上的网络规则。例如,当一个 Service 后端有多个 Pod 时,Kube - proxy 会根据负载均衡算法(如轮询、随机等),在节点上创建相应的 iptables 或 IPVS 规则,将发往 Service 虚拟 IP 地址的请求转发到后端对应的 Pod 上,从而实现服务的高可用性和高性能。同时,Kubernetes 还提供了 DNS 服务,为 Service 和 Pod 分配域名,使得它们可以通过域名进行访问,进一步简化了服务发现和通信的过程。例如,其他 Pod 可以通过访问my-service.default.svc.cluster.local这样的域名来访问名为 my-service 的 Service,而无需关心 Service 后端具体的 Pod IP 地址。
通过以上步骤,Kubernetes 实现了从用户提交请求到容器化应用在集群中运行的完整流程,各个组件之间紧密协作,确保了整个过程的高效性和可靠性。
三、K8S 网络原理
在 Kubernetes 集群中,网络是一个至关重要的组成部分,它就像人体的神经系统,负责各个组件之间的信息传递和协同工作。良好的网络设计和配置能够确保容器化应用在集群中高效、稳定地运行,实现组件之间的通信、服务的暴露以及网络访问的控制。下面我们来深入探讨 K8S 的网络原理。
3.1 网络模型目标
K8S 网络模型的设计目标是实现各个组件之间高效、无缝的通信。在这个模型中,每个 Pod 都拥有独立且可路由的 IP 地址,如同每个设备在传统网络中都有自己的 IP 一样。这意味着无论 Pod 位于集群中的哪个节点,它们之间都能直接通信,无需复杂的 NAT 转换。这种设计使得 Kubernetes 集群中的网络环境更加简单、高效,也更符合现代分布式系统的通信需求。例如,在一个由多个微服务组成的应用中,不同的微服务可能部署在不同的 Pod 中,通过 K8S 的网络模型,这些 Pod 之间可以直接通信,就像它们在同一个局域网中一样,大大简化了服务之间的通信架构。
3.2 Pod 内、同节点及不同节点间通信
在 Kubernetes 集群中,Pod 是最小的可部署和可管理的计算单元,了解 Pod 内部、同一节点上 Pod 之间以及不同节点上 Pod 之间的通信原理,对于理解 Kubernetes 网络至关重要。
3.2.1 Pod 内通信
一个 Pod 可以包含一个或多个紧密协作的容器。在 Pod 内部,这些容器共享相同的网络命名空间,这就好比它们在同一间屋子里,使用相同的网络接口和路由表。所以,Pod 内的容器之间通过localhost和端口号就能轻松通信,就像在同一台物理机上的进程间通信一样便捷。例如,一个 Pod 中同时运行着一个 Web 应用容器和一个数据库客户端容器,Web 应用容器可以通过localhost:3306直接访问数据库客户端容器提供的数据库服务,无需经过外部网络,大大提高了通信效率。
3.2.2 同节点 Pod 间通信
在同一节点上,每个 Pod 都有自己独立的网络命名空间和 IP 地址。当一个 Pod 要与同一节点上的另一个 Pod 通信时,数据会通过虚拟以太网设备(veth pair)进行转发。veth pair 的一端连接在 Pod 的网络命名空间内(表现为 eth0),另一端连接在节点的网络命名空间内(如 vethX)。数据从源 Pod 的 eth0 发出,经过 veth pair 到达节点网络,然后通过网桥(如 cbr0)转发到目标 Pod 对应的 veth 接口,最终进入目标 Pod。以一个简单的示例来说明,假设节点上有 Pod A 和 Pod B,Pod A 的 IP 为 10.244.0.2,Pod B 的 IP 为 10.244.0.3。当 Pod A 要向 Pod B 发送数据时,数据首先从 Pod A 的 eth0 发出,通过 veth pair 到达节点的网桥 cbr0,网桥根据目标 IP 地址 10.244.0.3,将数据转发到 Pod B 对应的 veth 接口,进而进入 Pod B,完成通信过程。
3.2.3 不同节点间 Pod 通信
不同节点间的 Pod 通信相对复杂一些。当源 Pod 发送数据时,数据先通过所在节点的 veth 接口和网桥到达节点的网络层。此时,节点会根据集群的路由表,将数据发送到目标 Pod 所在的节点。目标节点收到数据后,再通过自身的网桥和 veth 接口将数据转发到目标 Pod。这里的路由表由 K8s 网络插件(如 Flannel、Calico 等)负责维护和管理,确保数据能够准确无误地在不同节点间传输。例如,在一个跨节点的微服务架构中,前端服务 Pod 运行在 Node 1 上,后端服务 Pod 运行在 Node 2 上。当用户请求前端服务时,前端服务 Pod 需要与后端服务 Pod 通信获取数据。前端服务 Pod 发送的数据先通过 Node 1 的 veth 接口和网桥到达 Node 1 的网络层,Node 1 根据路由表将数据发送到 Node 2,Node 2 收到数据后,再通过自身的网桥和 veth 接口将数据转发到后端服务 Pod,从而完成整个通信流程,保障了微服务架构的正常运行。
3.3 服务的网络代理与暴露方式
在 Kubernetes 中,Service 是一种抽象的概念,它为一组 Pod 提供了一个稳定的访问入口,解决了 Pod 的动态变化(如重启、扩缩容)导致 IP 变化带来的访问问题。同时,Kubernetes 提供了多种服务暴露方式,以满足不同场景下的需求。
3.3.1 Service 网络代理
K8s 中的服务是一种抽象,它为一组 Pod 提供了一个稳定的访问入口。每个服务都有一个虚拟的 Cluster IP,当客户端访问这个 Cluster IP 时,kube - proxy 组件会将请求转发到后端实际的 Pod 上。kube - proxy 在每个节点上运行,它通过维护 IPtables 规则或基于 IPVS 的负载均衡器,实现将服务的虚拟 IP 映射到后端 Pod 的实际 IP。这种机制使得即使后端 Pod 的 IP 地址发生变化(比如 Pod 被重新调度),客户端也无需关心,依然可以通过服务的稳定 IP 进行访问。例如,一个电商应用的订单服务由多个 Pod 组成,这些 Pod 的 IP 地址可能会因为各种原因发生变化。通过 Service 和 kube - proxy,客户端只需要访问订单服务的 Cluster IP,kube - proxy 会自动将请求转发到当前可用的 Pod 上,保证了订单服务的稳定访问,无需客户端手动更新 Pod 的 IP 地址。
3.3.2 NodePort 服务类型
NodePort 是 K8s 中一种常用的服务暴露方式。它在集群中每个节点的一个特定端口(默认 30000 - 32767)上公开服务。外部客户端可以通过访问任意节点的 IP 地址加上这个特定的 NodePort 端口,就能访问到集群内部的服务。这种方式简单直接,适合用于测试环境或小型集群中快速暴露服务。例如,在开发一个新的 Web 应用时,我们可以将其服务类型设置为 NodePort,通过访问集群中任意节点的 IP 和对应的 NodePort 端口,就能在本地浏览器中快速测试 Web 应用的功能,无需复杂的配置和部署过程。
3.3.3 LoadBalancer 服务类型
在生产环境中,LoadBalancer 服务类型更为常用。它借助云提供商(如 AWS、GCP、阿里云等)的负载均衡器,将外部流量均匀地分发到集群内的多个节点上运行的服务实例。负载均衡器会自动检测后端服务的健康状况,当某个节点或 Pod 出现故障时,会自动将流量切换到其他正常的实例上,从而提供高可用性和可扩展性。不过,使用这种服务类型通常会产生一定的费用,因为涉及到云提供商的负载均衡器资源使用。以一个大型电商平台为例,在购物高峰期,大量用户同时访问平台,通过 LoadBalancer 服务类型,云提供商的负载均衡器可以将用户请求均匀地分配到集群中的各个节点和 Pod 上,确保平台能够稳定、高效地运行,为用户提供良好的购物体验,同时也保障了系统的高可用性和可扩展性,应对突发的流量高峰。
四、Ingress 资源与网络策略
在 Kubernetes 集群中,除了基本的网络通信和服务暴露方式,Ingress 资源和网络策略也起着重要的作用。Ingress 资源主要用于管理集群外部对内部服务的访问,而网络策略则用于实现细粒度的网络访问控制,保障集群的网络安全。
4.1 Ingress 资源
Ingress 是 K8s 中用于管理集群外部对内部服务访问的 API 对象。它就像是一个智能的流量管理员,能够根据定义的规则,将传入的 HTTP/HTTPS 请求路由到不同的后端服务。Ingress 可以实现基于域名、路径等多种条件的路由,还支持 SSL 终止、负载均衡等高级功能。通过 Ingress,我们可以在一个入口点统一管理多个服务的外部访问,使得集群对外的服务暴露更加灵活和高效。例如,一个企业的 Kubernetes 集群中部署了多个服务,如 Web 应用、API 服务、文件服务等。通过 Ingress,我们可以配置不同的域名或路径规则,将用户的请求准确地路由到相应的服务上。比如,将www.example.com的请求路由到 Web 应用服务,将api.example.com的请求路由到 API 服务,实现了多个服务通过一个入口点对外提供服务,同时还可以对不同的服务进行 SSL 证书配置和负载均衡设置,提高了服务的安全性和性能。
4.2 网络策略
网络策略是 K8s 提供的一种网络访问控制机制,用于限制 Pod 之间以及 Pod 与外部网络之间的流量。通过定义网络策略,我们可以实现细粒度的访问控制,比如只允许特定命名空间的 Pod 访问某个服务,或者禁止某个 Pod 访问外部网络等。要使用网络策略,必须确保所使用的网络插件(如 Calico)支持这一功能。以一个多租户的 Kubernetes 集群为例,不同租户的应用可能运行在同一个集群中。为了保证租户之间的网络隔离和安全性,可以通过定义网络策略,限制不同租户的 Pod 之间不能相互访问,每个租户只能访问自己命名空间内的资源以及特定开放的共享资源。这样就有效地避免了租户之间的网络干扰和潜在的安全风险,保障了每个租户应用的安全运行。
五、总结
Kubernetes 作为云原生时代的核心技术,以其强大的容器编排和管理能力,为我们构建和运维现代化应用提供了高效、可靠的解决方案。通过深入了解 Kubernetes 的原理,包括其架构、工作流程以及网络原理,我们能够更好地发挥它的优势,提升应用的部署效率、稳定性和可扩展性。无论是在小型开发团队,还是大型企业的复杂生产环境中,Kubernetes 都展现出了巨大的价值。
Tips: 为了大家快速高效的学习,已经将文章提交到了git仓库,涵盖后端大部分技术,以及后端学习路线,仓库内容会持续更新,建议 Star 收藏 以便随时查看https://gitee.com/bxlj/java-article。