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-JXBL7O23XHVFQV2I 和 KUBE-SEP-BBPDSOPRICLINLPY 中,流量分别被 DNAT 分配到了后端的 Pod(就绪的 Endpoints)。
  5. Pod 处理完数据请求,向客户端返回请求结果时,在 POSTROUTING 链上要对数据包做 SNAT 处理,以确保客户端接收到的数据包的源地址是其发送请求时的目标地址。

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

综上所述,iptables 模式最主要的链是 KUBE-SERVICES 、 KUBE-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 会非常庞大,对管理是个不小的负担,性能也会大打折扣。