k8s services iptables规则探究

结论

本文只讨论iptables的services实现,ipvs实现有所不同,这里先说结论如下:

  • service 使用iptables 来进行pod的dnat,services本身只是一条虚拟的iptables规则,不存在实体。
  • service 使用iptales 扩展模块来实现pod轮询策略故而无法实现最小链接数等负载算法
    • 多pod下的RR实现使用iptables statistic模块的random算法加权实现
    • sessionAffinity 使用iptables recent模块实现保持,功能主要依赖于nf_conntrack来实现连接标记

单pod时service iptables 规则实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# nginx pod ip地址:
$ kubectl describe pod nginx-fb8d45fxt-dcc1t | grep "IP"

IP: 10.200.1.21

# Service服务,通过172.30.13.253:80则实际访问到10.200.1.21:80
$ kubectl describe svc nginx
...
Type: ClusterIP
IP: 172.30.13.25
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.200.1.21:80
Session Affinity: None
...

$ iptables-save (选取部分关键规则)

...

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

...

-A KUBE-SEP-UWNFTKZFYWNNNTK7 -s 10.200.1.21/32 -m comment --comment "demo/nginx:" \
-j KUBE-MARK-MASQ
-A KUBE-SEP-UWNFTKZFYWNNNTK7 -p tcp -m comment --comment "demo/nginx:" \
-m tcp -j DNAT --to-destination 10.200.1.21:80
-A KUBE-SERVICES -d 172.30.13.25/32 -p tcp -m comment \
--comment "demo/nginx: cluster IP" -m tcp --dport 80 -j KUBE-SVC-1T7IBBNZDJ76
-A KUBE-SVC-1T7IBBNZDJ76 -m comment --comment "demo/nginx:" \
-j KUBE-SEP-UWNFTKZFYWNNNTK7

分析:

当访问 172.30.13.25/32 的80 端口时,iptables 规则会被第三条规则命中KUBE-SERVICES,在转发到 KUBE-SVC-1T7IBBNZDJ76 链 ,KUBE-SVC-1T7IBBNZDJ76链对流量进行comment标记之后 转发到 KUBE-SEP-UWNFTKZFYWNNNTK7
该链上实现了第一条访问外网的和一条对内的DNAT,此时是向内访问规则会命中第二条向内部进行DNAT 转发到pod地址上,进行路由寻址。


负载算法实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
$ kubectl scale deploy/nginx --replicas=3


$ iptables-save (选取部分规则)
-A KUBE-SEP-BI123VOIAZZ5S7 -s 10.129.1.12/32 -m comment --comment "demo/nginx:" \
-j KUBE-MARK-MASQ
-A KUBE-SEP-BI123VOIAZZ5S7 -p tcp -m comment --comment "demo/nginx:" \
-m tcp -j DNAT --to-destination 10.129.1.12:80

-A KUBE-SEP-CDQIKASRG66RK -s 10.129.1.13/32 -m comment --comment "demo/nginx:" \
-j KUBE-MARK-MASQ
-A KUBE-SEP-CDQIKASRG66RK -p tcp -m comment --comment "demo/nginx:" \
-m tcp -j DNAT --to-destination 10.129.1.13:80

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

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

-A KUBE-SVC-1T7IBBNZDJ76 -m comment --comment "demo/nginx:" \
-m statistic --mode random --probability 0.33332999982 -j KUBE-SEP-BI123VOIAZZ5S7
-A KUBE-SVC-1T7IBBNZDJ76 -m comment --comment "demo/nginx:" \
-m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-CDQIKASRG66RK
-A KUBE-SVC-1T7IBBNZDJ76 -m comment --comment "demo/nginx:" \
-j KUBE-SEP-W5HTO42ZVNHJQWBG

分析:

iptable 在实现多pod 负载算法的时候使用了 statistic模块的random 加权算法 -m statistic --mode random --probability 0.33332999982来实现。具体模块用法可以参考:http://ipset.netfilter.org/iptables-extensions.man.html


会话保持

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
$ kubectl edit svc nginx
...
sessionAffinity: ClientIP
sessionAffinityConfig:
clientIP:
timeoutSeconds: 3600
...

$ iptables-save (选取部分规则)
-A KUBE-SEP-BI123VOIAZZ5S7 -s 10.129.1.12/32 -m comment --comment "demo/nginx:" \
-j KUBE-MARK-MASQ
-A KUBE-SEP-BI123VOIAZZ5S7 -p tcp -m comment --comment "demo/nginx:" \
-m recent --set --name KUBE-SEP-BI123VOIAZZ5S7 --mask 255.255.255.255 \
--rsource -m tcp -j DNAT --to-destination 10.129.1.12:80

...

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

-A KUBE-SVC-1T7IBBNZDJ76 -m comment --comment "demo/nginx:" \
-m recent --rcheck --seconds 3600 --reap --name KUBE-SEP-BI123VOIAZZ5S7 \
--mask 255.255.255.255 --rsource -j KUBE-SEP-BI123VOIAZZ5S7

...

-A KUBE-SVC-1T7IBBNZDJ76 -m comment --comment "demo/nginx:" \
-m statistic --mode random --probability 0.33332999982 -j KUBE-SEP-BI123VOIAZZ5S7
-A KUBE-SVC-1T7IBBNZDJ76 -m comment --comment "demo/nginx:" \
-m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-CDQIKASRG66RK
-A KUBE-SVC-1T7IBBNZDJ76 -m comment --comment "demo/nginx:" \
-j KUBE-SEP-W5HTO42ZVNHJQWBG

分析

iptables 主要使用recent 模块来标记追踪连接状态 -m recent --rcheck --seconds 3600来完成会话保持。具体recent模块用法可以参考:http://ipset.netfilter.org/iptables-extensions.man.html