Kubernetes (K8s) 中 Service (SVC) 如何转发流量介绍

发布时间: 更新时间: 总字数:2438 阅读时间:5m 作者: IP上海 分享 网址

本文介绍 Kubernetes (K8s) 中 Service (SVC) 是如何将流量路由到其后端 Endpoints (即 Pod) 的原理。由 Kubernetes 集群中的多个核心组件协同工作的结果。我们可以将其分解为两大阶段:服务发现流量转发

服务发现 (Service Discovery)

解决 我该把请求发往哪里?

当一个 Pod(我们称之为客户端 Pod)想要访问另一个服务(比如一个名为 my-app 的 Service)时,它首先需要知道把网络请求发送到哪个 IP 地址。这时,Kubernetes 内置的 DNS 服务 CoreDNS 就登场了。

  1. 自动生成的 DNS 记录:当你创建一个 Service 时,Kubernetes 会自动在内部的 CoreDNS 中为其创建一个 DNS A 记录。这个记录的格式通常是 <service-name>.<namespace>.svc.cluster.local。例如,在 default 命名空间下创建一个名为 my-app 的 Service,它对应的 DNS 名称就是 my-app.default.svc.cluster.local
  2. 解析 Service Name 到 ClusterIP:这个 DNS 记录会解析到该 Service 的 ClusterIP。ClusterIP 是一个由 Kubernetes 分配的、稳定的、仅在集群内部可访问的虚拟 IP 地址。
  3. Pod 内的 DNS 查询:客户端 Pod 的 /etc/resolv.conf 文件被自动配置为使用集群内的 CoreDNS 服务器。因此,当你在代码中使用 http://my-app 这样的服务名称时,Pod 的 DNS 解析器会向 CoreDNS 发起查询。
  4. 获取 ClusterIP:CoreDNS 收到查询后,会返回 my-app 这个 Service 对应的 ClusterIP。

至此,客户端 Pod 已经知道了请求的目标 IP 地址,也就是这个虚拟的 ClusterIP。

流量转发 (Traffic Forwarding)

虚拟 IP 背后真正的目的地是谁?

现在客户端 Pod 向这个虚拟的 ClusterIP 发送数据包了。但 ClusterIP 本身并不与任何网络设备绑定,它只是一个占位符。真正将流量从这个虚拟 IP 转发到后端真实 Pod IP 的幕后英雄是 kube-proxy

kube-proxy 是一个运行在 Kubernetes 集群中每个 Node 上的网络代理和负载均衡器。它会监视 (watch) Kubernetes API Server 上关于 Service 和 Endpoints (或 EndpointSlice) 对象的变化,然后根据这些变化在节点上设置相应的转发规则。

这个转发过程主要通过以下几种模式实现:

核心组件:Endpoints Controller

在讨论 kube-proxy 的模式之前,必须先了解 Endpoints Controller。它是 kube-controller-manager 的一部分,负责维护 Service 和 Pod 之间的关联关系。

  • 监视:它会持续监视 Service 及其关联的 Pod (通过 Service 的 selector 标签选择器)。
  • 更新 Endpoints 对象:当一个 Service 所关联的 Pod 发生变化时(例如,Pod 创建、销毁、IP 变更、健康检查失败),Endpoints Controller 会立即更新与该 Service 同名的 Endpoints 对象。这个对象里包含了所有健康后端 Pod 的实际 IP 地址和端口列表。
  • **通知 kube-proxy**kube-proxy 通过监视 Endpoints 对象的变化,来获取最新的、可用的后端 Pod IP 列表。

kube-proxy 的工作模式

kube-proxy 将流量从 Service ClusterIP 路由到后端 Pod IP,主要有以下三种模式:

iptables 模式 (默认模式,最常用)

这是当前 Kubernetes 的默认模式,稳定且可靠。

  • 原理kube-proxy 会为集群中的每一个 Service 创建一系列的 iptables 规则。这些规则被写入到每个节点的 nat 表中。
  • 工作流程
  1. 捕获流量 (DNAT):当一个数据包的目的地址是某个 Service 的 ClusterIP:Port 时,它会被 KUBE-SERVICES 这条 iptables 链捕获。
  2. 负载均衡:这条链会再跳转到对应 Service 的专属链 (例如 KUBE-SVC-XXX)。在这个专属链里,包含了到每一个后端 Pod 的转发规则。kube-proxy 会使用 statistic 模块,通过概率(默认是均等的)随机选择一个后端 Pod。
  3. 修改目标地址:选定一个后端 Pod 后,iptables 规则会执行 DNAT (Destination Network Address Translation),将数据包的目标 IP 和端口从 Service 的 ClusterIP:Port 修改为被选中的 Pod 的实际 IP:Port。
  4. 路由转发:修改完目标地址后,Linux 内核就会根据节点的路由表,将这个数据包正确地转发给目标 Pod(无论这个 Pod 是在当前节点还是在其他节点)。
  • 优点:非常成熟和稳定。
  • 缺点:当 Service 数量非常多(成千上万)时,iptables 规则会变得很长,查找匹配规则的性能会下降,因为 iptables 是一个链式匹配的结构。

IPVS (IP Virtual Server) 模式

为了解决 iptables 模式在大规模集群下的性能问题,Kubernetes 引入了 IPVS 模式。

  • 原理:IPVS 本身就是 Linux 内核中用于高性能负载均衡的一个模块。kube-proxy 在此模式下,不再生成大量的 iptables 规则,而是通过 netlink 接口去创建和管理 IPVS 规则。
  • 工作流程
  1. kube-proxy 会为每个 Service 创建一个 IPVS 虚拟服务器 (Virtual Server),并将 Service 的 ClusterIP:Port 作为其地址。
  2. 然后,它会将从 Endpoints 对象中获取到的后端 Pod IP:Port 列表作为这个虚拟服务器的 真实服务器 (Real Server)
  3. 当访问 Service ClusterIP 的流量到达节点时,会被内核的 IPVS 模块直接接管。IPVS 使用更高效的哈希表来存储规则,能够非常快速地找到对应的虚拟服务器,并根据预设的负载均衡算法(如轮询、最少连接等)选择一个真实服务器(Pod),然后将流量转发过去。
  • 优点

  • 高性能和高扩展性:即使有大量的 Service,也能保持近乎恒定的查找性能。

  • 更丰富的负载均衡算法

  • 缺点:需要节点内核支持并加载 IPVS 模块。

userspace 模式 (已废弃)

这是最古老、性能最差的模式,不推荐使用。它在用户空间实现了一个真正的代理进程。所有到 ClusterIP 的流量都会先进入内核,然后被重定向到用户空间的 kube-proxy 进程,kube-proxy 再与后端某个 Pod 建立连接,并在两者之间来回转发数据。这个过程涉及多次内核态和用户态的切换,开销巨大。

总结流程

将整个流程串联起来:

  1. 创建与关联:管理员创建 Deployment 和 Service。Endpoints Controller 发现新 Pod 并将其 IP 添加到与 Service 关联的 Endpoints 对象中。
  2. 规则同步:每个节点上的 kube-proxy 检测到 Service 和 Endpoints 的变化,并根据所选模式(如 iptables)在节点上创建或更新相应的转发规则。
  3. 服务发现:客户端 Pod 通过查询集群 DNS (CoreDNS) 将 Service 名称 (my-app) 解析为虚拟的 ClusterIP。
  4. 流量发出:客户端 Pod 向这个 ClusterIP 发送请求数据包。
  5. 转发与路由:数据包到达节点(可以是客户端 Pod 所在的节点,也可以是其他节点),被节点上的 iptablesIPVS 规则捕获。
  6. 负载均衡与 DNAT:规则根据负载均衡策略选择一个健康的后端 Pod,并将数据包的目标地址从 ClusterIP 修改为该 Pod 的真实 IP。
  7. 到达终点:内核将修改后的数据包通过 CNI 提供的集群网络路由到最终的目标 Pod。

通过这套精巧的设计,Kubernetes 实现了应用与其底层 Pod 实例的解耦,为开发者提供了稳定、可靠的服务访问入口,同时保证了整个系统的动态性和可扩展性。

本文总阅读量 次 本站总访问量 次 本站总访客数
Home Archives Categories Tags Statistics