探究K8S Service内部iptables路由规则

栏目: 后端 · 发布时间: 5年前

内容简介:​ 在​ 为便于讲解,我们先创建如下应用及​ 作者的

前言

​ 在 K8S 集群内部,应用常使用 Service 互访,那么,了解 Service 技术优缺点将有利于应用规划与部署,鉴于此,本文将通过简单案例以探索 Cluster-Ip 类型 Service 服务的利弊。

​ 为便于讲解,我们先创建如下应用及 Service 服务:

# kubectl run --image=nginx nginx-web-1 --image-pull-policy='IfNotPresent'
# kubectl expose deployment nginx-web-1 --port=80 --target-port=80

Service 探索

​ 作者的 K8S 环境是 1.9 版本,其 Service 内部服务由 Kube-Proxy 提供,且默认用 iptables 技术实现,故本文探索 K8S 集群 Service 技术,即研究 iptablesK8S 上的技术实现。

Service Route (服务路由)

​ 如下可知,通过 nginx-web-1 服务可实际访问到后端 pod

# nginx pod ip地址:
# kubectl describe pod nginx-web-1-fb8d45f5f-dcbtt | grep "IP"
IP:             10.129.1.22

# Service服务,通过172.30.132.253:80则实际访问到10.129.1.22:80
# kubectl describe svc nginx-web-1 
...
Type:              ClusterIP
IP:                172.30.132.253
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         10.129.1.22:80
Session Affinity:  None
...

# 重置nginx web页面:
# kubectl exec -it nginx-web-1-fb8d45f5f-dcbtt -- \
               sh -c "echo hello>/usr/share/nginx/html/index.html"

# curl 10.129.1.22
hello
# curl 172.30.132.253
hello

Service 服务分配的 CLUSTER-IP 以及监听的端口均虚拟的,即在 K8S 集群节点上执行 ip anetstat -an 命令均无法找到,其实际上, IPPort 是由 iptables 配置在每 K8S 节点上的。在节点上执行如下命令可找到此 Service 相关的 iptables 配置,简析如下:

  1. 当通过 Service 服务 IP:172.30.132.253:80 访问时,匹配第 3 条规则链( KUBE-SERVICES )后,跳转到第 4 条子链( KUBE-SVC-... )上;
  2. 4 条子链做简单注释后,继而跳转到第 1、2 规则链( KUBE-SEP-... )上;
  3. 当源 Pod 通过 Service 访问自身时,匹配第 1 条规则,继而跳转到 KUBE-MARK-MASQ 链中;
  4. 匹配到第 2 条规则,此时通过 DNAT 被重定向到后端 Pod:108.29.1.22:80
# iptables-save | grep nginx-web-1
-A KUBE-SEP-UWNFTKZFYWNNNTK7 -s 10.129.1.22/32 -m comment --comment "demo/nginx-web-1:" \
   -j KUBE-MARK-MASQ
-A KUBE-SEP-UWNFTKZFYWNNNTK7 -p tcp -m comment --comment "demo/nginx-web-1:" \
   -m tcp -j DNAT --to-destination 10.129.1.22:80
-A KUBE-SERVICES -d 172.30.132.253/32 -p tcp -m comment \
   --comment "demo/nginx-web-1: cluster IP" -m tcp --dport 80 -j KUBE-SVC-SNP24T7IBBNZDJ76
-A KUBE-SVC-SNP24T7IBBNZDJ76 -m comment --comment "demo/nginx-web-1:" \
   -j KUBE-SEP-UWNFTKZFYWNNNTK7

​ 详细分析 iptables 规则,执行 iptables-save 命令可发现 natPREROUTINGOUTPUT 链中均有 KUBE-SERVICES 规则链,且处于第一顺位。

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

当通过 Service 访问应用时,流量经由 nat 表中的 PREROUTING 规则链处理后,跳转到 KUBE-SERVICES 子链,而此链包含了对具体 Service 处理的规则。如下所示,访问 172.30.132.253:80 将被跳转到 KUBE-SEP-... 子规则链中。

-A KUBE-SERVICES -d 172.30.132.253/32 -p tcp -m comment \
   --comment "demo/nginx-web-1: cluster IP" -m tcp --dport 80 -j KUBE-SVC-SNP24T7IBBNZDJ76
-A KUBE-SVC-SNP24T7IBBNZDJ76 -m comment --comment "demo/nginx-web-1:" \
   -j KUBE-SEP-UWNFTKZFYWNNNTK7

​ 如下所示, KUBE-SEP-... 子链存在两条规则:

  1. 1 条规则: Pod 通过 Service 访问自身时匹配,此规则仅作标记( MARK )处理;
  2. 2 条规则:通过 DNAT 重定向到后端 Pod 实例上,至此,通过 Service 最终将流量导向到后端实例上;
-A KUBE-SEP-UWNFTKZFYWNNNTK7 -s 10.129.1.22/32 -m comment --comment "demo/nginx-web-1:" \
   -j KUBE-MARK-MASQ
-A KUBE-SEP-UWNFTKZFYWNNNTK7 -p tcp -m comment --comment "demo/nginx-web-1:" \
   -m tcp -j DNAT --to-destination 10.129.1.22:80

-A KUBE-MARK-MASQ -j MARK --set-xmark 0x1/0x1

Loadbalance (负载均衡)

​ 执行如下命令将 Deployment 扩展为 3Pod 后,继而再观察 Service 负载均衡方面的技术或问题。

# kubectl scale deploy/nginx-web-1 --replicas=3

​ 再次 dump 防火墙规则,发现 Service 经由 iptablesstatistic 模块,以 random 方式均衡的分发流量,也即负载均衡模式为 轮训

  1. 存在 3DNATKUBE-MARK-MASQ 规则,分别对应 3 个后端 Pod 实地址;
  2. KUBE-SERVICES 链中存在 3 条子链,除最后一条 KUBE-SVC-... 子链外,其余子链使用模块 statisticrandom 模式做流量分割或负载均衡:第 1KUBE-SVC-... 应用 33% 流量,第 2KUBE-SVC-... 规则应用剩余的 50% 流量,第 3KUBE-SVC-... 规则应用最后的流量。
# iptables-save | grep nginx-web-1
-A KUBE-SEP-BI762VOIAZZWU5S7 -s 10.129.1.27/32 -m comment --comment "demo/nginx-web-1:" \
   -j KUBE-MARK-MASQ
-A KUBE-SEP-BI762VOIAZZWU5S7 -p tcp -m comment --comment "demo/nginx-web-1:" \
   -m tcp -j DNAT --to-destination 10.129.1.27:80

-A KUBE-SEP-CDQIKEVSTA766BRK -s 10.129.1.28/32 -m comment --comment "demo/nginx-web-1:" \
   -j KUBE-MARK-MASQ
-A KUBE-SEP-CDQIKEVSTA766BRK -p tcp -m comment --comment "demo/nginx-web-1:" \
   -m tcp -j DNAT --to-destination 10.129.1.28:80

-A KUBE-SEP-W5HTO42ZVNHJQWBG -s 10.129.3.57/32 -m comment --comment "demo/nginx-web-1:" \
   -j KUBE-MARK-MASQ
-A KUBE-SEP-W5HTO42ZVNHJQWBG -p tcp -m comment --comment "demo/nginx-web-1:" \
   -m tcp -j DNAT --to-destination 10.129.3.57:80

-A KUBE-SERVICES -d 172.30.132.253/32 -p tcp -m comment \
   --comment "demo/nginx-web-1: cluster IP" -m tcp --dport 80 -j KUBE-SVC-SNP24T7IBBNZDJ76

-A KUBE-SVC-SNP24T7IBBNZDJ76 -m comment --comment "demo/nginx-web-1:" \
   -m statistic --mode random --probability 0.33332999982 -j KUBE-SEP-BI762VOIAZZWU5S7
-A KUBE-SVC-SNP24T7IBBNZDJ76 -m comment --comment "demo/nginx-web-1:" \
   -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-CDQIKEVSTA766BRK
-A KUBE-SVC-SNP24T7IBBNZDJ76 -m comment --comment "demo/nginx-web-1:" \
   -j KUBE-SEP-W5HTO42ZVNHJQWBG

Session Affinity (会话保持)

​ 如下所示,调整 Service 服务,打开会话保持功能,并设置会话保持期限为 3 小时( PS :若不设置,则默认是 3 小时):

# kubectl edit svc nginx-web-1
...
  sessionAffinity: ClientIP
  sessionAffinityConfig:
    clientIP:
      timeoutSeconds: 10800
...

​ 继续观察 iptables 实现,发现在原有基础上, iptables 规则中添加了 recent 模块,此模块被用于会话保持功能,故 kube-proxy 通过在 iptables 中结合 statisticrecent 模块,实现了 Service 的轮训负载均衡与会话保持功能。

  1. 通过 Service 服务访问应用,封包进入 KUBE-SERVICES 规则链,并跳转到 KUBE-SVC-... 子链中;
  2. KUBE-SVC-SNP... 子链中, recent 位于 statistic 模块前,故而,有如下情况出现:

    • 当客户端第一次访问 Service 时, KUBE-SVC-... 子链中的规则( -m recent --rcheck --seconds 10800 --reap ...--rsource )池中未记录客户端地址,故封包匹配失败,从而封包被后续的 statistic 模块规则处理后,均衡分发到 KUBE-SEP-... 子链中,此链中使用 recent 模块的 --set 参数将客户源地址记录到规则池后, DNAT 到实际后端实例上;
    • KUBE-SVC-... 子链中 recent 模块配置了源地址记录期限,若客户端 3--seconds 10800 --reap )小时内未访问服务,则 recent 规则池中的客户端记录将被移除,此时客户端再次访问 Service 就如同第一次访问 Service 一样;
    • 当客户端在 3 小时内再次访问 Service 时,匹配 KUBE-SVC-... 子链中的 recent 模块规则后,跳转到 KUBE-SEP 子链,其规则中 recent 模块 --set 参数将更新规则池中的 Record TTL ,而后 DNAT 到实际后端实例上;
# iptables-save | grep nginx-web-1
-A KUBE-SEP-BI762VOIAZZWU5S7 -s 10.129.1.27/32 -m comment --comment "demo/nginx-web-1:" \
   -j KUBE-MARK-MASQ
-A KUBE-SEP-BI762VOIAZZWU5S7 -p tcp -m comment --comment "demo/nginx-web-1:" \
   -m recent --set --name KUBE-SEP-BI762VOIAZZWU5S7 --mask 255.255.255.255 \
   --rsource -m tcp -j DNAT --to-destination 10.129.1.27:80
# 省略2条类似的KUBE-SEP规则
...

-A KUBE-SERVICES -d 172.30.132.253/32 -p tcp -m comment \
   --comment "demo/nginx-web-1: cluster IP" -m tcp --dport 80 -j KUBE-SVC-SNP24T7IBBNZDJ76

-A KUBE-SVC-SNP24T7IBBNZDJ76 -m comment --comment "demo/nginx-web-1:" \
   -m recent --rcheck --seconds 10800 --reap --name KUBE-SEP-BI762VOIAZZWU5S7 \
   --mask 255.255.255.255 --rsource -j KUBE-SEP-BI762VOIAZZWU5S7
# 省略2条类似的KUBE-SVC规则
...

-A KUBE-SVC-SNP24T7IBBNZDJ76 -m comment --comment "demo/nginx-web-1:" \
   -m statistic --mode random --probability 0.33332999982 -j KUBE-SEP-BI762VOIAZZWU5S7
-A KUBE-SVC-SNP24T7IBBNZDJ76 -m comment --comment "demo/nginx-web-1:" \
   -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-CDQIKEVSTA766BRK
-A KUBE-SVC-SNP24T7IBBNZDJ76 -m comment --comment "demo/nginx-web-1:" \
   -j KUBE-SEP-W5HTO42ZVNHJQWBG

总结

K8S 中的 Service 服务可提供负载均衡及会话保持功能,其通过 Linux 内核 netfilter 模块来配置 iptables 实现,网络封包在内核中流转,且规则匹配很少,故效率非常高;而 Service 负载均衡分发比较薄弱,其通过 statisticrandom 规则实现轮训分发,无法实现复杂的如 最小链接 分发方式,鉴于此, K8S 1.9 后续版本调整了 kube-proxy 服务,其可通过 ipvs 实现 Service 负载均衡功能。

  1. K8S 1.9 版本可使用kube-router替换 kube-proxy ,且可使用 ipvs 替换 iptables 来实现 service 服务。

以上所述就是小编给大家介绍的《探究K8S Service内部iptables路由规则》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

关乎天下

关乎天下

关明生 / 学林出版社 / 2005-8 / 8.00元

《关乎天下:中小企业赢取江山的秘诀》收录了作者多年在大企业(如阿里巴巴网站)从事管理基层得到的经验,可为众多中小企业提供招贤纳士和销售管理方面的新思路。一起来看看 《关乎天下》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

html转js在线工具
html转js在线工具

html转js在线工具