浅谈kubernetes ingress机制
Overview
ingress在将流量发往后端的时候是不经过kube-proxy的,ingress controller会直接和kube-apiserver进行交互,然后获取pod endpoints和service的对应关系,进行轮询,负载均衡到后端节点。
一、验证试验
从集群中删除kube-proxy,查看通过ingress的方式是否可以访问成功?
1# 实验中选择的是"iptables模式的kube-proxy"
2# 首先关闭kube-proxy
3$ sudo systemctl stop kube-proxy
4
5# 查看服务,ClusterIP的端口是8080,NodePort的端口是30948
6$ ks
7NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
8example-test NodePort 10.0.0.226 <none> 8080:30948/TCP 18h
9traefik NodePort 10.0.0.85 <none> 9000:30001/TCP,80:30002/TCP,443:31990/TCP 19h
10
11# 查看与"10.0.0.226"有关的iptables条目,得知访问"10.0.0.226"且目的端口是"8080"的流量会发送给KUBE-SVC-KNYNFDNL67C7KAZZ链
12$ sudo iptables -S -t nat | grep 10.0.0.226
13-A KUBE-SERVICES ! -s 10.0.0.0/24 -d 10.0.0.226/32 -p tcp -m comment --comment "traffic-dispatcher/example-test:port-8080 cluster IP" -m tcp --dport 8080 -j KUBE-MARK-MASQ
14-A KUBE-SERVICES -d 10.0.0.226/32 -p tcp -m comment --comment "traffic-dispatcher/example-test:port-8080 cluster IP" -m tcp --dport 8080 -j KUBE-SVC-KNYNFDNL67C7KAZZ
15
16# 查看KUBE-SVC-KNYNFDNL67C7KAZZ链发现,采用的是"--probability"策略,进行后端两个pod的负载均衡
17$ sudo iptables -S -t nat | grep KUBE-SVC-KNYNFDNL67C7KAZZ
18-N KUBE-SVC-KNYNFDNL67C7KAZZ
19-A KUBE-NODEPORTS -p tcp -m comment --comment "traffic-dispatcher/example-test:port-8080" -m tcp --dport 30948 -j KUBE-SVC-KNYNFDNL67C7KAZZ
20-A KUBE-SERVICES -d 10.0.0.226/32 -p tcp -m comment --comment "traffic-dispatcher/example-test:port-8080 cluster IP" -m tcp --dport 8080 -j KUBE-SVC-KNYNFDNL67C7KAZZ
21-A KUBE-SVC-KNYNFDNL67C7KAZZ -m comment --comment "traffic-dispatcher/example-test:port-8080" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-O6MCO5C4JB4A4VEJ
22-A KUBE-SVC-KNYNFDNL67C7KAZZ -m comment --comment "traffic-dispatcher/example-test:port-8080" -j KUBE-SEP-KREF3VGT6NHFYTVH
23
24# 我们再看后面转发的"KUBE-SEP-KREF3VGT6NHFYTVH", 得知这一步就发送给了真实的pod
25$ sudo iptables -t nat -L KUBE-SEP-KREF3VGT6NHFYTVH --line-numbers
26Chain KUBE-SEP-KREF3VGT6NHFYTVH (1 references)
27num target prot opt source destination
281 KUBE-MARK-MASQ all -- 10.244.2.4 anywhere /* traffic-dispatcher/example-test:port-8080 */
292 DNAT tcp -- anywhere anywhere /* traffic-dispatcher/example-test:port-8080 */ tcp to:10.244.2.4:8080
30
31# 现在我们要模拟不能走kube-proxy添加的规则访问到服务,于是我们删除刚刚"50%/50%"规则进行负载均衡转发的那两条规则(kube-proxy本质就是负载均衡)
32$ sudo iptables -t nat -L KUBE-SVC-KNYNFDNL67C7KAZZ --line-numbers
33Chain KUBE-SVC-KNYNFDNL67C7KAZZ (2 references)
34num target prot opt source destination
351 KUBE-SEP-O6MCO5C4JB4A4VEJ all -- anywhere anywhere /* traffic-dispatcher/example-test:port-8080 */ statistic mode random probability 0.50000000000
362 KUBE-SEP-KREF3VGT6NHFYTVH all -- anywhere anywhere /* traffic-dispatcher/example-test:port-8080 */
37
38# 删除规则
39$ sudo iptables -t nat -D KUBE-SVC-KNYNFDNL67C7KAZZ 1 2
现在以ClusterIP+Port的方式访问服务应该走不通了,测试访问:
1$ ks
2NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
3example-test NodePort 10.0.0.226 <none> 8080:30948/TCP 18h
4traefik NodePort 10.0.0.85 <none> 9000:30001/TCP,80:30002/TCP,443:31990/TCP 19h
5$ curl 10.0.0.226:8080
6访问失败
7$ curl 10.20.13.90:30948
8访问失败
9$ curl 10.20.13.90:30002 -H 'Host:testfile.shannonai.com'
10访问成功, 由此证明ingress是不走kube-proxy的!
二、结论
-
kube-proxy的工作是附加一些转发规则,所以说单单的"systemctl stop kube-proxy"是不会影响已经存在的规则的,也就是原来可以走通的服务只要没有变化,就依旧可以走通;只是我们再添加新的服务,就不能走通了(因为没有kube-proxy为我们添加这些规则了); 另外多节点的集群,只要其他节点的kube-proxy是ok的,就已经可以从其他节点访问服务; 我们做了上述那么多破坏如果想要恢复的话,也只是需要重新"systemctl restart kube-proxy"就会自动把我们破坏掉的规则加回来
-
如何理解我们集群的ClusterIP和他对应的端口?我们了解过kube-proxy的规则了之后就很明显的可以得出结论:
1)pod的ip是pod所处的networkns的真实ip,通过veth和网桥和我们宿主机的真实ip通信
2)clusterip仅仅为kube-proxy的iptables或者ipvs规则匹配所用,也就是并不会出现在本机进行路由1# 本机的路由表只能看到真实的节点ip段和网络插件附加的pod ip段, 没有clusterip的地址段 2$ route -n 3内核 IP 路由表 4目标 网关 子网掩码 标志 跃点 引用 使用 接口 50.0.0.0 10.20.13.1 0.0.0.0 UG 100 0 0 ens5 610.20.13.0 0.0.0.0 255.255.255.0 U 0 0 0 ens5 710.20.13.1 0.0.0.0 255.255.255.255 UH 100 0 0 ens5 810.244.1.0 10.244.1.0 255.255.255.0 UG 0 0 0 flannel.1 910.244.2.0 10.244.2.0 255.255.255.0 UG 0 0 0 flannel.1 10172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0 11 12# iptables和ipvs的规则中可以看到clusterip的地址段 13$ sudo iptables -S -t nat | grep 10.0.0.226 14-A KUBE-SERVICES ! -s 10.0.0.0/24 -d 10.0.0.226/32 -p tcp -m comment --comment "traffic-dispatcher/example-test:port-8080 cluster IP" -m tcp --dport 8080 -j KUBE-MARK-MASQ 15-A KUBE-SERVICES -d 10.0.0.226/32 -p tcp -m comment --comment "traffic-dispatcher/example-test:port-8080 cluster IP" -m tcp --dport 8080 -j KUBE-SVC-KNYNFDNL67C7KAZZ
-
由此得出,pod的targetport在对于不同的pod的情况下是可以重复的;nodeport如果是处于同一个节点是不能重复的;clusterip在clusterip的地址不同(也就是iptables和ipvs的规则中不冲突/或者简单理解为不同服务)的情况下是可以重复的
参考链接: https://xuxinkun.github.io/2016/07/22/kubernetes-proxy/