kubernetes Service 详解

Kubernetes 的 Service 代表的是 Kubernetes 后端服务的入口,它主要包含服务的访问 IP(虚拟 IP)和端口,工作在 L4.

Service 只存储服务的入口信息(IP:PORT),不存储后端 Pod 信息,Service 是通过 Label Selector 选择与之匹配的后端 Pod。当被 Service 选择的后端 Pod 运行且能正常向外提供服务时,Kubernetes 的 Endpoint Controller 会生成一个新的 Endpoint 对象,指向此 Pod 的 IP:PORT。Service 接收到访问请求,会将请求转发到对应的 Endpoint。同时,Service 的访问 IP 和 Endpoint/Pod 的 IP 都会在 Kubernetes 的 DNS 服务里面进行注册以记录域名和 IP 的对应关系,因此用户可以在集群中通过域名的方式访问 Service 和 Pod。

用户创建 Service 后,Kubernetes 会从集群的可用服务 IP 池中为 Service 分配一个稳定的集群内访问 IP,称为 Cluster IP。Kubernetes 还会通过注册 DNS 条目为 Cluster IP 分配 域名(主机名)。Cluster IP域名 在集群内是独一无二的,并且在服务的整个生命周期中保持不变,直到将 Service 从集群中删除,Kubernetes 才会释放 Cluster IP域名 。通过此方法,Service 作为代理,向客户端提供了稳定不变的访问后端服务的入口。

Service 除了作为 代理 功能,同时也提供了 负载均衡高可用。当后端的 Pod 有多个时,默认会通过 轮询 将请求流量均匀分布到多个 Pod 上,当某个 Pod 不可用是,Service 不会将请求调度到问题节点。

Kubernetes 使用节点上运行的 kube-proxy 组件管理各 Service 和后端 Pod 的连接。kube-proxy 是一个基于出战流量的 负载均衡控制器,它监控 Kubernetes API Service 并持续将 Service IP (ClusterIP)映射到运行状况良好的后端 Pod,具体实现是通过主机上的 iptables/IPVS 的规则。访问 Service 的 IP 会被这些(路由)规则直接 DNAT 到后端 Pod 的 IP。

Service 配置语法参考

环境信息

  • Centos 7 3.10.0-1160
  • Kubernetes v1.24.7

kube-proxy iptables 模式下的规则解析

kube-proxy 默认使用 iptables 模式实现 Service 的代理转发和负载均衡。检查 kube-proxy 使用的代理模式

本示例使用相关信息如下

$ kubectl get services 
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
api-service ClusterIP 10.106.126.96 <none> 10302/TCP 145d

$ kubectl get endpoints api-service
NAME ENDPOINTS AGE
api-service 10.244.3.138:10302,10.244.4.120:10302 145d


针对 api-service,后端的 Pod 就绪后,生成了 ENDPOINTS,kube-proxy 会为该服务创建以下 iptables 规则

-A PREROUTING -m comment --comment "kubernetes service portals" -j KUBE-SERVICES

-A KUBE-SERVICES -d 10.106.126.96/32 -p tcp -m comment --comment "default/api-service:api-pord cluster IP" -m tcp --dport 10302 -j KUBE-SVC-DVTQLPR6DVOLBZS4

-A KUBE-SVC-DVTQLPR6DVOLBZS4 ! -s 10.244.0.0/16 -d 10.106.126.96/32 -p tcp -m comment --comment "default/api-service:api-pord cluster IP" -m tcp --dport 10302 -j KUBE-MARK-MASQ
-A KUBE-SVC-DVTQLPR6DVOLBZS4 -m comment --comment "default/api-service:api-pord -> 10.244.3.138:10302" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-JXBL7O23XHVFQV2I
-A KUBE-SVC-DVTQLPR6DVOLBZS4 -m comment --comment "default/api-service:api-pord -> 10.244.4.120:10302" -j KUBE-SEP-BBPDSOPRICLINLPY

-A KUBE-SEP-JXBL7O23XHVFQV2I -s 10.244.3.138/32 -m comment --comment "default/api-service:api-pord" -j KUBE-MARK-MASQ
-A KUBE-SEP-JXBL7O23XHVFQV2I -p tcp -m comment --comment "default/api-service:api-pord" -m tcp -j DNAT --to-destination 10.244.3.138:10302

-A KUBE-SEP-BBPDSOPRICLINLPY -s 10.244.4.120/32 -m comment --comment "default/api-service:api-pord" -j KUBE-MARK-MASQ
-A KUBE-SEP-BBPDSOPRICLINLPY -p tcp -m comment --comment "default/api-service:api-pord" -m tcp -j DNAT --to-destination 10.244.4.120:10302

-A POSTROUTING -m comment --comment "flanneld masq" -j FLANNEL-POSTRTG
-A POSTROUTING -m comment --comment "kubernetes postrouting rules" -j KUBE-POSTROUTING-A FLANNEL-POSTRTG -m mark --mark 0x4000/0x4000 -m comment --comment "flanneld masq" -j RETURN
-A FLANNEL-POSTRTG -s 10.244.0.0/16 -d 10.244.0.0/16 -m comment --comment "flanneld masq" -j RETURN
-A FLANNEL-POSTRTG -s 10.244.0.0/16 ! -d 224.0.0.0/4 -m comment --comment "flanneld masq" -j MASQUERADE
-A FLANNEL-POSTRTG ! -s 10.244.0.0/16 -d 10.244.3.0/24 -m comment --comment "flanneld masq" -j RETURN
-A FLANNEL-POSTRTG ! -s 10.244.0.0/16 -d 10.244.0.0/16 -m comment --comment "flanneld masq" -j MASQUERADE

-A KUBE-POSTROUTING -m mark ! --mark 0x4000/0x4000 -j RETURN
-A KUBE-POSTROUTING -j MARK --set-xmark 0x4000/0x0
-A KUBE-POSTROUTING -m comment --comment "kubernetes service traffic requiring SNAT" -j MASQUERADE

具体工作流程如下:

  1. 所有进入 PREROUTING 链的流量会被跳转到 KUBE-SERVICES 自定义链
  2. 本示例中请求 api-service 的访问数据包(目的地址为 10.106.126.96:10302)在 PREROUTING 链中被 -d 10.106.126.96/32 -p tcp -m comment --comment "default/api-service:api-pord cluster IP" -m tcp --dport 10302 匹配到,根据规则跳转到自定义链 KUBE-SVC-DVTQLPR6DVOLBZS4
  3. 在自定义链 KUBE-SVC-DVTQLPR6DVOLBZS4 中,实现了负载均衡,一半的流量会被跳转到链 KUBE-SEP-JXBL7O23XHVFQV2I,另一半的流量会被跳转到 KUBE-SEP-BBPDSOPRICLINLPY
  4. 在自定义链 KUBE-SEP-JXBL7O23XHVFQV2IKUBE-SEP-BBPDSOPRICLINLPY 中,流量分别被 DNAT 分配到了后端的 Pod(就绪的 Endpoints)。
  5. Pod 处理完数据请求,向客户端返回请求结果时,在 POSTROUTING 链上要对数据包做 SNAT 处理,以确保客户端接收到的数据包的源地址是其发送请求时的目标地址。

通过以上 kube-proxy 管理的规则,Service 实现了对后端 Pod 的服务代理及负载均衡功能。

综上所述,iptables 模式最主要的链是 KUBE-SERVICESKUBE-SVC-*KUBE-SEP-*

  • KUBE-SERVICES - 访问集群服务的数据包入口,它会根据匹配到的目标 IP:PORT 将数据包分发到相应的链 KUBE-SVC-*
  • KUBE-SVC-* - 相当于一个负载均衡器,它会将数据包平均分配到 KUBE-SEP-* 链。每个 KUBE-SVC-* 链后面的 KUBE-SEP-* 链的数量和 Service 后端就绪的 Pod 数量一致。
  • KUBE-SEP-* - 通过 DNAT 将数据包的目的地址(IP:PORT)修改为后端就绪的 Pod 的 IP:PORT,从而将流量转发到相应的 Pod

kube-proxy 的 iptables 模式因为使用 DNAT 转发数据包,存在一定的性能损耗,另外,当集群中的 Service 数量上万时,节点上的 iptables rules 会非常庞大,对管理是个不小的负担,性能也会大打折扣。