一文搞懂 Kubernetes Service 网络原理

为什么需要Service ?

由于 Kubernetes 环境中 Pod 的动态特性,分配给它们的 IP 地址不是静态的。 它们是短暂的,并且每次创建或删除 Pod 时都会发生变化。

Service解决了这个问题,并提供了一种稳定的机制来连接到一组 pod。主要解决了服务怎么提供给第三方使用的问题。

默认情况下,当您在 Kubernetes 中创建服务时,会保留并分配一个虚拟 IP。 从那里,您可以使用选择器将服务关联到目标 Pod。 删除 pod 并添加新 pod 时会发生什么情况? 该服务的虚拟IP保持静态且不变。 但是,流量将到达新创建的 Pod,无需干预。 换句话说,Kubernetes 中的Service 类似于负载均衡器。

但它们是如何工作的呢?

使用 Netfilter 和 Iptables 拦截和重写流量

Kubernetes 中的服务基于两个 Linux 内核组件构建: 网络过滤器和 iptables。

  • Netfilter 是一个框架,允许配置数据包过滤、创建 NAT 或端口转换规则以及管理网络中的流量。 此外,它还屏蔽并防止未经请求的连接访问服务。
  • Iptables 是一个用户空间实用程序,允许您配置 Linux 内核防火墙的 IP 数据包过滤规则。

iptables 是建立在 netfilter 框架之上的用户空间工具。 是内核级别的框架,而 则是用户空间中的工具,用于配置和管理这个框架。

iptables 作为不同的 Netfilter 模块实现。 您可以使用 iptables CLI 动态更改过滤规则并将其插入 netfilters 挂钩点。 过滤器组织在不同的表中,其中包含用于处理网络流量数据包的链。 每个协议使用不同的内核模块和程序。

当提到 iptables 时,通常意味着用于 IPv4。对于 IPv6 规则,CLI 称为 ip6tables。

iptables 有五种类型的链,每种链都直接映射到 Netfilter 的钩子。 从 iptables 的角度来看,它们是:

  • PRE_ROUTING
  • INPUT
  • FORWARD
  • OUTPUT
  • POST_ROUTING

它们相应地映射到 Netfilter 钩子:

  • NF_IP_PRE_ROUTING
  • NF_IP_LOCAL_IN
  • NF_IP_FORWARD
  • NF_IP_LOCAL_OUT
  • NF_IP_POST_ROUTING

当数据包到达时,根据它所处的阶段,它将"触发"Netfilter 钩子,该钩子应用特定的 iptables 过滤。图片来自 learnk8s

看起来很复杂,不过不用担心。这就是我们使用 Kubernetes 的原因,以上所有内容都是通过使用Service进行抽象的,并且简单的 YAML 定义会自动设置这些规则。 如果您有兴趣查看 iptables 规则,可以连接到节点并运行:

ruby 复制代码
$ iptables-save

您还可以使用此工具可视化节点上的 iptables 链。 具有可视化 iptables 链的示例图

可能配置了数百条规则。想象一下手工去配置这数百条规则有多么麻烦。

我们已经解释了当 Pod 位于相同和不同节点时 Pod 到 Pod 的通信是如何发生的。 在 Pod-to-Service 中,通信的前半部分保持不变。

当请求从 Pod-A 开始,并且想要到达 Pod-B(在本例中将位于Service"后面")时,传输中途会发生额外的更改,原始请求通过 Pod-A 命名空间中的 eth0 接口退出, 从那里,它穿过 veth 对并到达根命名空间以太网桥。 一旦到达网桥,数据包就会立即通过默认网关转发。

与 Pod 到 Pod 部分一样,主机进行按位比较,并且由于服务的 vIP 不是节点 CIDR 的一部分,因此数据包将立即通过默认网关转发。

如果默认网关的 MAC 地址尚未出现在查找表中,则相同的 ARP 解析将会找到该地址。

现在关键的事情发生了, 就在数据包通过节点的路由过程之前,NF_IP_PRE_ROUTING Netfilter 挂钩被触发,并应用 iptables 规则。该规则会进行 DNAT 更改,并且重写Pod的A数据包目的IP。

先前的服务 vIP 目标被重写为 Pod-B的 IP 地址。 从iptables 转化之后开始,路由就与直接进行 Pod 到 Pod 通信一样。

然而,在所有这些通信之间,还利用了另一个第三个功能conntrack(连接跟踪)。 当 Pod-B 发回响应时,Conntrack 会将数据包与连接相关联,并且跟踪其来源。

NAT 严重依赖 conntrack 来工作, 如果没有连接跟踪,它就不知道将包含响应的数据包发送回哪里, 使用 conntrack 时,可以使用相同的源或目标 NAT 更改设置数据包的返回路径。

返回请求的另一半现在按相反的顺序排列。 Pod-B 接收并处理了请求,现在将数据发送回 Pod-A。 接下来会发生什么呢?

Service的响应

现在 Pod-B 发送响应,将其 IP 地址设置为源,将 Pod A 的 IP 地址设置为目标。

其余的都是一样的; SNAT 完成后,数据包到达根命名空间中的以太网桥,并通过 veth 对转发到 Pod-A。

一个网络包从应用程序到发出去经过的步骤

至此我们了解了Service的网络原理。 现在我们回过头看 k8s负载均衡 代码是如何实现的就很好理解了,整体的代码都是在维护 iptables 的规则,并且由于 iptables 会存在一定的性能问题,所以通过接口的抽象能够灵活的替换底层功能的实现。

相关推荐
条纹布鲁斯2 小时前
dockerdsktop修改安装路径/k8s部署wordpress和ubuntu
docker·kubernetes
登云时刻5 小时前
Kubernetes集群外连接redis集群和使用redis-shake工具迁移数据(一)
redis·kubernetes·bootstrap
吴半杯6 小时前
gateway漏洞(CVE-2022-22947)
docker·kubernetes·gateway
灼烧的疯狂10 小时前
K8S + Jenkins 做CICD
容器·kubernetes·jenkins
wenyue112111 小时前
Revolutionize Your Kubernetes Experience with Easegress: Kubernetes Gateway API
容器·kubernetes·gateway
Python私教14 小时前
ubuntu搭建k8s环境详细教程
linux·ubuntu·kubernetes
O&REO15 小时前
单机部署kubernetes环境下Overleaf-基于MicroK8s的Overleaf应用部署指南
云原生·容器·kubernetes
politeboy15 小时前
k8s启动springboot容器的时候,显示找不到application.yml文件
java·spring boot·kubernetes
运维小文16 小时前
K8S资源限制之LimitRange
云原生·容器·kubernetes·k8s资源限制
登云时刻16 小时前
Kubernetes集群外连接redis集群和使用redis-shake工具迁移数据(二)
redis·容器·kubernetes