K8s之ClusterIP的实现原理分析
在k8s集群中,每个pod有自己独立的podIP及服务端口,但为了保证pod重启后(重启后IP发生变化,这不同于传统的物理机或虚拟环境)对客户端保持透明,k8s引入了clusterIP的概念,clusterIP用于集群间服务调用,对于外部是不可访问的,这个IP同时是个不存在的IP,k8s通过iptables实现了clusterIP的负载均衡及重启透明。到了这里算是柳暗花明了吧,我们测试环境中的三个
在k8s集群中,每个pod有自己独立的podIP及服务端口,但为了保证pod重启后(重启后IP发生变化,这不同于传统的物理机或虚拟环境)对客户端保持透明,k8s引入了clusterIP的概念,clusterIP用于集群间服务调用,对于外部是不可访问的,这个IP同时是个不存在的IP,k8s通过iptables实现了clusterIP的负载均衡及重启透明。
今天我们通过测试环境的iptables分析来展示clusterIP的实现,测试集群包括10.244.1.3、10.244..2.3、10.244.3.3三个节点,每个节点都活跃一个frontendpod,如下:
root@dev-4-control-plane# sh svc.sh
namespace is:default
|NAME |CLUSTERIP |PORT |TARGETPORT |ENDPOINTS
|frontend |10.96.214.50 |<unset>%80/TCP |80/TCP |10.244.1.3:80,10.244.2.3:80,10.244.3.3:80
由于clusterIP用于集群间服务调用,对于调用方而言clusterIP到后端endpoint的负载均衡及NAT转换位于调用方iptables的OUTPUT链路上,如下:
#1:root@dev-4-worker# iptables -t nat -nvL OUTPUT //可以看到这个服务交给了KUBE-SERVICES
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
427 29227 KUBE-SERVICES all -- * * 0.0.0.0/0 0.0.0.0/0 /* kubernetes service portals */
2 120 CNI-HOSTPORT-DNAT all -- * * 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
那么我们看看KUBE-SERVICE链中做了什么?
#2:root@dev-4-worker# iptables -t nat -nvL KUBE-SERVICES
Chain KUBE-SERVICES (2 references)
pkts bytes target prot opt in out source destination
0 0 KUBE-SVC-YU5RV2YQWHLZ5XPR tcp -- * * 0.0.0.0/0 10.96.165.129 /* default/redis-follower cluster IP */ tcp dpt:6379
0 0 KUBE-SVC-LRNEBRA3Z5YGJ4QC tcp -- * * 0.0.0.0/0 10.96.21.91 /* default/redis-leader cluster IP */ tcp dpt:6379
0 0 KUBE-SVC-ENODL3HWJ5BZY56Q tcp -- * * 0.0.0.0/0 10.96.214.50 /* default/frontend cluster IP */ tcp dpt:80
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
上面的内容中可以看到对于目的地址为10.96.214.50(frontend的clusterIP) 且目标端口为80的调用交给了KUBE-SVC-ENODL3HWJ5BZY56Q链,那么看看KUBE-SVC-ENODL3HWJ5BZY56Q链中做了什么呢?
#3:root@dev-4-worker:/jinfh# iptables -t nat -nvL KUBE-SVC-ENODL3HWJ5BZY56Q
Chain KUBE-SVC-ENODL3HWJ5BZY56Q (1 references)
pkts bytes target prot opt in out source destination
0 0 KUBE-MARK-MASQ tcp -- * * !10.244.0.0/16 10.96.214.50 /* default/frontend cluster IP */ tcp dpt:80
0 0 KUBE-SEP-PUYWAIYQ7Z2WPEMT all -- * * 0.0.0.0/0 0.0.0.0/0 /* default/frontend -> 10.244.1.3:80 */ statistic mode random probability 0.33333333349
0 0 KUBE-SEP-BVLU66VZEIAHD7Y7 all -- * * 0.0.0.0/0 0.0.0.0/0 /* default/frontend -> 10.244.2.3:80 */ statistic mode random probability 0.50000000000
0 0 KUBE-SEP-XH63RNNYRQN757HJ all -- * * 0.0.0.0/0 0.0.0.0/0 /* default/frontend -> 10.244.3.3:80 */
到了这里算是柳暗花明了吧,我们测试环境中的三个podIP终于在这里出现了。 这里定义了三条链路,分别对应10.244.1.3、10.244.2.3及10.244.3.3三个pod上的服务,其中1.3链路负载1/3的交易,2.3链路负载1/2的交易,而3.3链路则负载剩余1/6交易。接下来我们再看看这几条链路的具体定义,如下:
#4.1:root@dev-4-worker# iptables -t nat -nvL KUBE-SEP-PUYWAIYQ7Z2WPEMT
Chain KUBE-SEP-PUYWAIYQ7Z2WPEMT (1 references)
pkts bytes target prot opt in out source destination
0 0 KUBE-MARK-MASQ all -- * * 10.244.1.3 0.0.0.0/0 /* default/frontend */
0 0 DNAT tcp -- * * 0.0.0.0/0 0.0.0.0/0 /* default/frontend */ tcp to:10.244.1.3:80
#4.2root@dev-4-worker# iptables -t nat -nvL KUBE-SEP-BVLU66VZEIAHD7Y7
Chain KUBE-SEP-BVLU66VZEIAHD7Y7 (1 references)
pkts bytes target prot opt in out source destination
0 0 KUBE-MARK-MASQ all -- * * 10.244.2.3 0.0.0.0/0 /* default/frontend */
0 0 DNAT tcp -- * * 0.0.0.0/0 0.0.0.0/0 /* default/frontend */ tcp to:10.244.2.3:80
#4.3root@dev-4-worker# iptables -t nat -nvL KUBE-SEP-XH63RNNYRQN757HJ
Chain KUBE-SEP-XH63RNNYRQN757HJ (1 references)
pkts bytes target prot opt in out source destination
0 0 KUBE-MARK-MASQ all -- * * 10.244.3.3 0.0.0.0/0 /* default/frontend */
0 0 DNAT tcp -- * * 0.0.0.0/0 0.0.0.0/0 /* default/frontend */ tcp to:10.244.3.3:80
从上面的链路定义中可以看到,每个链路分别包含一个DNAT操作,即destination NAT,也就将目标IP(clusterIP)进行转换,三条链路分别将转换成10.244.1.3:80、10.244.2.3:80、10.244.4.3:80,即我们交易网络数据流出时clusterIP:serverPort的组合会转换成对应链路后端的podIP: containerPort组合。
到这里,读者大概看到通过iptables是如何实现clusterIP的了吧?
最后我们在看一下,去往三条链路的网络数据是怎么流出的,如下:
#5:root@dev-4-worker:/jinfh# route -n //通过路由表可以看到10.244.1.3、10.244.3.3的流量通过eth0分别转发到72.18.0.2、172.18.0.4,而10.244.2.3的流量则由虚拟网卡进行处理
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 172.18.0.1 0.0.0.0 UG 0 0 0 eth0
10.244.0.0 172.18.0.5 255.255.255.0 UG 0 0 0 eth0
10.244.1.0 172.18.0.2 255.255.255.0 UG 0 0 0 eth0
10.244.2.2 0.0.0.0 255.255.255.255 UH 0 0 0 vethc528da70
10.244.2.3 0.0.0.0 255.255.255.255 UH 0 0 0 veth321d2a93
10.244.3.0 172.18.0.4 255.255.255.0 UG 0 0 0 eth0
从上图可以看到,流向集群内其他节点的数据通过eth0流出,网关分别对应pod所在node的nodeIP,而本机数据则是通过veth(node上每个pod都有一个对应的veth)流出。
更多推荐
所有评论(0)