和 Service 相关的任何事情都由每个节点上运行的 kube-proxy 进程处理。开始的时候, kube-proxy 确实是一个 proxy,等待连接,对每个进来的连接,连接到一个 pod。这称为 userspace(用户空间)代理模式。 后来,性能更好的 iptables 代理模式取代了它。

Service 的 IP 地址是虚拟的, 没有被分配给任何网络接口,当数据包离开节点时也不会列为数据包的源或目的 IP 地址。Service 的一个关键细节是,它们包含一个 IP、端口对,所以服务IP本身并不代表任何东西。这就是为什么你不能够 ping 它们。

service 本身就是一套 iptables 规则,不存在实体,所以也不能 ping 通。

最近在做开源之夏的时候也遇到了这种情况,我还傻傻的在 ping 它。

kube-proxy 如何使用 iptables

当在 API 服务器中创建一个 service 时,虚拟 IP 地址立刻就会分配给它。之后很短时间内, API服务器会通知所有运行在工作节点上的 kube-proxy 客户端有一个新 service 已经被创建了。然后,每个 kube-proxy 都会让该服务在自己的运行节点上可寻址。原理是通过建立一些 iptables 规则,确保每个目的地为服务的 IP/端口对的数据包被解析,目的地址被修改,这样数据包就会被重定向到支持服务的一个 pod。

除了监控 API 对 Service 的更改, kube-proxy 也监控对 Endpoint 对象的更改。Endpoint 对象保存所有支持服务的 pod 的IP/端口对。这就是为什么 kube-proxy 必须监听所有 Endpoint 对象。毕竟 Endpoint 对象在每次新创建或删除支持 pod 时都会发生变更,当 pod 的就绪状态发生变化或者 pod 的标签发生变化,就会落入或超出服务的范畴(采用就绪探针和存活探针)。

发送数据包给 service 会发生什么?

包目的地初始设置为服务的 IP 和端口(在本例中, Service是在 172.30.0.1:80)。发送到网络之前,节点 A 的内核会根据配置在该节点上的 iptables 规则处理数据包。

内核会检查数据包是否匹配任何这些 iptables 规则。其中有个规则规定如果有任何数据包的目的地 IP等于 172.30.0.1 、目的地端口等于 80,那么数据包的目的地 IP 和端口应该被替换为随机选中的 pod 的 IP 和端口。