K8S-iptables与ipvs规则

K8S – lptables -ipvs 了解

lptables实现流量转发与负载均衡

lptables如何做流量转发?
>DNAT实现P地址和端口映射
iptables -t nat -A PREROUTING -d 1.2.3.4/32 --dport 80 -j DNAT -to-destination 10.20.30.40:8080

Iptables如何做负载均衡?
>statistic模块为每个后端设置权重,k8s默认的没有使用权重,随机的
iptables t nat-A PREROUTING -d 1.2.3.4 --dport 80 -m statistic -mode random -probability .25 -j DNAT --to-destination 10.20.30.40:8080

lptables如何做会话保持?
>recent模块设置会话保持时间
iptables t nat-A FO0 -m recent--rcheck --seconds 3600 --reap -name BAR -j BAR

lptables在Kubernetes的应用举例

kube-proxy 修改了filter和nat表,它对 iptables 的链进行了扩充,自定义了KUBE-SERVICES,KUBE-NODEPORTS,KUBE-POSTROUTING,KUBE-MARK-MASQ 和 KUBE-MARK-DROP 五个链,并主要通过为 KUBE-SERVICES 链(附着在PREROUTING 和 OUTPUT)增加 rule 来配制 traffic routing 规则
Cluster IP: Port -> PREROUTING(OUTPUT) -> KUBE-SERVICES ->KUBE-SVC-XXX-> KUBE-SEP-XXX -> Pod IP:Target Port
Chain PREROUTING (policy ACCEPT)
target        prot    opt  source     destination 
KUBE-SERVICES all      --  0.0.0.0/0  0.0.0.0/0

Chain KUBE-SERVICES (2 references)
target         prot    opt  source     destination
KUBE-SVC-6IM33IEVEEV703GP tcp --0.0.0.0/0 10.20.30.40 tcp dpt:80

Chain KUBE-SVC-6IM33IEVEEV703GP (1 references)
target   prot opt source   destination
KUBE-SEP-Q3UCPZ54E6Q2R4UT all -- 0.0.0.0/0  0.0.0.0/0

Chain KUBE-SEP-Q3UCPZ54E6Q2R4UT (1 references)
target   prot opt source  destination
DNAT     tcp  --  0.0.0.0/0  0.0.0.0/0  tcp to:172.17.0.2:8080
实现10.20.30.40:80   到 172.17.0.2:8080  DNAT转换

Iptables做负载均衡的问题

·规则线性匹配时延
-KUBE-SERVICES链挂了一长串KUBE-SVC-*链; 访问每个service,要遍历每条链直到匹配,时间复杂度O(N)
·规则更新时延  非增量式
·可扩展性
-当系统存在大量iptables规则链时,增加/删除规则(内核全量的copy出,更改再copy进去)会出现kernel lock
lemel lock: Another app is currently holding the xtables lock. Perhaps you want to use the-w option?
·可用性
-后端实例扩容,服务会话保持时间更新等都会导致连接断开。

更新lptables规则的时延

时延出现在哪?
-非增量式(全量更新),即使加上no-flush(iptables-restore)选项
-Kube-proxy定期同步iptables状态:
*拷贝所有规则:iptables-save
*在内存中更新规则
*在内核中修改规则:iptables-restore
*规则更新期间存在kernel 1ock

5K service (4OK 规则),增加一条iptables规则,耗时11min.
20K service (160K 规则),增加一条iptables规则,耗时5h

lptables周期性刷新导致TPS抖动

什么是IPVS (IP Virtual Server)
	Linux内核实现的L4 LB,LVS负载均衡的实现
    基于netfilter, hash table
	支持TCP, UDP, SCTP协议,IPV4, IPV6
	支持多种负载均衡策略 -rr, wrr, lc wlc, sh, dh, lblc...
	支持会话保持  persistent connection调度算法
IPVS三种转发模式
支持三种LB模式: Direct Routing(DR),Tunneling,NAT
- DR模式工作在L2,最快,但不支持端口映射
- Tunneling模式用IP包封装IP包,也称IPIP模式,不支持端口映射`
- DR和Tunneling模式,回程报文不会经过IPVS Director
- NAT模式支持端口映射,回程报文经过IPVS Director  内核原生版本只做DNAT,不做SNAT

IPVS做L4转发
1.绑定VIP
- dummy网卡
# ip link add dev dummy0 type dummy
#ip addr add 192.168.2.2/32 dev dummy0-
本地路由表
#ip route add to local 192.168.2.2/32 dev eth0 proto kernel
-网卡别名
袂ifconfig etho:1 192.168.2.2 netmask 255.255.255.255 up
2.创建IPVS Virtual Server
# ipvsadm -A t 192.168.60.200:80 -s rr -p 600   #-p回话保持600s
3.创建IPVS Real Server
# ipvsadm -a -t 192.168.60.200:80 -r 172.17.1.2:80 -m
# ipvsadm -a -t 192.168.60.200:80 -r 172.17.2.3:80 -m

Iptables VS. IPVS
lptables
√灵活,功能强大
√在prerouting, postrouting, forward, input, output不同阶段都能对包进行操作
IPVS
√更好的性能(hash vs. chain)
更多的负载均衡算法
-rr,wrr, Ic, wlc, ip hash...
√连接保持
- IPVS service更新期间,保持连接不断开
√预先加载内核模
-nf_ conntrack_ipv4, ip_vs, ip_vs_rr, ip_vs_wrr,ipvs_sh...√
# echo 1 >/proc/sys/net/ipv4/vs/conntrack    #打开,nat模式要使用

为什么还需要Iptables

因为我们访问了一层Service IP
Node IP-> Service IP ( Gateway) ->Container

客户端:(Node IP,Service IP),期望:(Service IP, Node IP) 
但实际,经过IPVS一层转发,包地址变成了(Node IP,Container)
服务端发出:(Container, Node IP)→这个包的源/目的地址与客户端期望的不一样!故将被丢弃

因此,需要一次SNAT(masquerade欺骗)!!source NAT
(Node IP,Service IP)->(IPVS director IP, Container)

这也是为什么IPVS NAT模式要求回程报文必须经过director 
提问:为什么Container A-> Cluster IP-> Container B?

IPSet 
ipset支持“增量”式增/删/改,而非iptables式全量更新, 把O(N)的iptables规则降为O(1),不用想太多iptables...

ipset create KUBE-LOOP-BACK hash:ip,port,ip
ipset add KUBE-LOOP-BACK 192.168.1.1,udp:53,192.168.1.1
ipset add KUBE-LOOP-BACK 192.168.1.2,tcp:80,192.168.1.2
...

iptables  只写一条,匹配上面的KUBE-LOOP-BACK即可
iptablest nat-A POSTROUTING -m set --match-set KUBE-LOOP-BACK dst,dst,src -j MASQUERADEOUTING 

ipset +IPVS+ iptables

service生成的iptables规则(了解,抄过来的,原帖找不到了)

cluster ip工作原理

调用方是某个node上面的某个POD,它向cluster ip 172.17.185.22发起调用,所以走的是OUTPUT链。

iptables要做的事情,就是识别dst(目标IP)是172.17.185.22的包,把dst改写成某一个Endpoints的IP地址(这个service背后对应2个endpoints)。

我们从output链开始看:

[root@10-42-8-102 ~]# iptables -t nat -nvL OUTPUT
Chain OUTPUT (policy ACCEPT 4 packets, 240 bytes)
 pkts bytes target     prot opt in     out     source               destination         
3424K  209M KUBE-SERVICES  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */

直接交给KUBE-SERVICES链了,继续看:

[root@10-42-8-102 ~]# iptables -t nat -nvL KUBE-SERVICES
Chain KUBE-SERVICES (2 references)
pkts bytes target     prot opt in     out     source               destination     
0     0 KUBE-MARK-MASQ  tcp  --  *      *      !172.17.0.0/16        172.17.185.22        /* zhongce-v2-0/testapi-smzdm-com: cluster IP */ tcp dpt:809
0     0 KUBE-SVC-G3OM5DSD2HHDMN6U  tcp  --  *      *       0.0.0.0/0            172.17.185.22        /* zhongce-v2-0/testapi-smzdm-com: cluster IP */ tcp dpt:809
10   520 KUBE-FW-G3OM5DSD2HHDMN6U  tcp  --  *      *       0.0.0.0/0            10.42.162.216        /* zhongce-v2-0/testapi-smzdm-com: loadbalancer IP */ tcp dpt:809

对结果进行了截取,只保留了属于该Service的规则

上述3条规则是顺序执行的:

  • 第1条规则匹配发往Cluster IP 172.17.185.22的流量,跳转到了KUBE-MARK-MASQ链进一步处理,其作用就是打了一个MARK,稍后展开说明。

  • 第2条规则匹配发往Cluster IP 172.17.185.22的流量,跳转到了KUBE-SVC-G3OM5DSD2HHDMN6U链进一步处理,稍后展开说明。

  • 第3条规则匹配发往集群外LB IP的10.42.162.216的流量,跳转到了KUBE-FW-G3OM5DSD2HHDMN6U链进一步处理,稍后展开说明。

打MARK这一步还不是很重要,所以我们先说第2条规则,显然第2条规则对发往Cluster IP的流量要做dst IP改写到具体的一个Endpoints上面,我们看一下:

[root@10-42-8-102 ~]# iptables -t nat -nvL KUBE-SVC-G3OM5DSD2HHDMN6U
Chain KUBE-SVC-G3OM5DSD2HHDMN6U (3 references)
 pkts bytes target     prot opt in     out     source               destination         
   18   936 KUBE-SEP-JT2KW6YUTVPLLGV6  all  --  *      *       0.0.0.0/0            0.0.0.0/0            statistic mode random probability 0.50000000000
   21  1092 KUBE-SEP-VETLC6CJY2HOK3EL  all  --  *      *       0.0.0.0/0            0.0.0.0/0

一共2条规则,每条规则的应用概率是0.5,其实就是负载均衡流量到这2条链的意思,而这2条链分别对应各自endpoints的DNAT规则:

[root@10-42-8-102 ~]# iptables -t nat -nvL KUBE-SEP-JT2KW6YUTVPLLGV6
Chain KUBE-SEP-JT2KW6YUTVPLLGV6 (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 KUBE-MARK-MASQ  all  --  *      *       10.42.147.255        0.0.0.0/0       
   26  1352 DNAT       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp to:10.42.147.255:809
[root@10-42-8-102 ~]# iptables -t nat -nvL KUBE-SEP-VETLC6CJY2HOK3EL
Chain KUBE-SEP-VETLC6CJY2HOK3EL (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 KUBE-MARK-MASQ  all  --  *      *       10.42.38.222         0.0.0.0/0           2   104 DNAT       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp to:10.42.38.222:809

这样就实现了在调用方完成负载均衡逻辑,也就是Cluster IP的工作原理了。

流量经过本机路由表决定从eth0 LAN出去(ucloud是underlay扁平网络):

[root@10-42-8-102 ~]# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         10.42.0.1       0.0.0.0         UG    0      0        0 eth0
10.42.0.0       0.0.0.0         255.255.0.0     U     0      0        0 eth0

在流量离开本机之前会经过POSTROUTING链:

[root@10-42-8-102 ~]# iptables -t nat -nvL POSTROUTING
Chain POSTROUTING (policy ACCEPT 274 packets, 17340 bytes)
 pkts bytes target     prot opt in     out     source               destination         
 632M   36G KUBE-POSTROUTING  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kubernetes postrouting rules */
 
[root@10-42-8-102 ~]# iptables -t nat -nvL KUBE-POSTROUTING
Chain KUBE-POSTROUTING (1 references)
 pkts bytes target     prot opt in     out     source               destination         
  526 27352 MASQUERADE  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kubernetes service traffic requiring SNAT */ mark match 0x4000/0x4000

其实直接就跳转到了KUBE-POSTROUTING,然后匹配打过0x4000 MARK的流量,将其做SNAT转换,而这个MARK其实就是之前没说的KUBE-MARK-MASQ做的事情:

[root@10-42-8-102 ~]# iptables -t nat -nvL KUBE-MARK-MASQ
Chain KUBE-MARK-MASQ (183 references)
 pkts bytes target     prot opt in     out     source               destination         
  492 25604 MARK       all  --  *      *       0.0.0.0/0            0.0.0.0/0            MARK or 0x4000

也就是说,当流量离开本机时,src IP会被修改为node的IP,而不是发出流量的POD IP了。

最后还有一个KUBE-FW-G3OM5DSD2HHDMN6U链没有讲,从本机发往LB IP的流量要做啥事情呢?

其实也是让流量直接发往具体某个Endpoints,就别真的发往LB了,这样才能获得最佳的延迟:

[root@10-42-8-102 ~]# iptables -t nat -nvL KUBE-FW-G3OM5DSD2HHDMN6U
Chain KUBE-FW-G3OM5DSD2HHDMN6U (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    2   104 KUBE-MARK-MASQ  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* zhongce-v2-0/testapi-smzdm-com: loadbalancer IP */
    2   104 KUBE-SVC-G3OM5DSD2HHDMN6U  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* zhongce-v2-0/testapi-smzdm-com: loadbalancer IP */
    0     0 KUBE-MARK-DROP  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* zhongce-v2-0/testapi-smzdm-com: loadbalancer IP */

其中第2条规则就是复用了之前我们看到的负载均衡链。

nodeport工作原理

nodeport就是在每个node上开放同一个端口,只要集群外访问node上的该端口就可以访问到对应的service。

因此,iptables此时的目标是dst IP是node自己,并且dst port是nodeport端口的流量,将其直接改写到service的某个endpoints。

其实该匹配规则也是写在PREROUTING链上的,具体在KUBE-SERVICES链上,在之前的结果里面我没有贴出来而已:

[root@10-42-8-102 ~]# iptables -t nat -nvL KUBE-SERVICES
Chain KUBE-SERVICES (2 references)
 pkts bytes target     prot opt in     out     source               destination     
    0     0 KUBE-MARK-MASQ  tcp  --  *      *      !172.17.0.0/16        172.17.185.22        /* zhongce-v2-0/testapi-smzdm-com: cluster IP */ tcp dpt:809
    0     0 KUBE-SVC-G3OM5DSD2HHDMN6U  tcp  --  *      *       0.0.0.0/0            172.17.185.22        /* zhongce-v2-0/testapi-smzdm-com: cluster IP */ tcp dpt:809
   10   520 KUBE-FW-G3OM5DSD2HHDMN6U  tcp  --  *      *       0.0.0.0/0            10.42.162.216        /* zhongce-v2-0/testapi-smzdm-com: loadbalancer IP */ tcp dpt:809
    0     0 KUBE-NODEPORTS  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kubernetes service nodeports; NOTE: this must be the last rule in this chain */ ADDRTYPE match dst-type LOCAL

处理nodeport的规则在末尾,只要dst IP是node本机IP的话(–dst-type LOCAL),就跳转到KUBE-NODEPORTS做进一步判定:

[root@10-42-8-102 ~]# iptables -t nat -nvL KUBE-NODEPORTS
Chain KUBE-NODEPORTS (1 references)
 pkts bytes target     prot opt in     out     source               destination        
    0     0 KUBE-MARK-MASQ  tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            /* zhongce-v2-0/testapi-smzdm-com: */ tcp dpt:39746
    0     0 KUBE-SVC-G3OM5DSD2HHDMN6U  tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            /* zhongce-v2-0/testapi-smzdm-com: */ tcp dpt:39746

我只保留了与该service相关的2条规则:

  • 第1条匹配dst port如果是39746,那么就打mark。
  • 第2条匹配dst port如果是39746,那么就跳到负载均衡链做DNAT改写。
  • 否则就不做任何处理,流量继续交给后续链条处理。

路由表

[root@10-42-8-102 ~]# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         10.42.0.1       0.0.0.0         UG    0      0        0 eth0
10.42.0.0       0.0.0.0         255.255.0.0     U     0      0        0 eth0
10.42.2.81      0.0.0.0         255.255.255.255 UH    0      0        0 vethc739b9e3
10.42.8.62      0.0.0.0         255.255.255.255 UH    0      0        0 veth1e24e60d
10.42.24.222    0.0.0.0         255.255.255.255 UH    0      0        0 veth95162021

因为使用ucloud的CNI插件,所以网络是一个underlay模式,Node和POD的IP段是直通的。

当被调用的node收到流量的时候,经过PREROUTING链什么也不做,经过路由表后可以判定转发给哪个虚拟网卡,从而将流量FORWARD到具体的docker容器内。

关于K8S Service的分析就到这里,我觉得比较重要的一点认识是:K8S集群内调用LB IP并不会真的发给LB,仍旧是直接走了集群内的负载均衡。

  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值