浅谈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的!

二、结论

  1. kube-proxy的工作是附加一些转发规则,所以说单单的"systemctl stop kube-proxy"是不会影响已经存在的规则的,也就是原来可以走通的服务只要没有变化,就依旧可以走通;只是我们再添加新的服务,就不能走通了(因为没有kube-proxy为我们添加这些规则了); 另外多节点的集群,只要其他节点的kube-proxy是ok的,就已经可以从其他节点访问服务; 我们做了上述那么多破坏如果想要恢复的话,也只是需要重新"systemctl restart kube-proxy"就会自动把我们破坏掉的规则加回来

  2. 如何理解我们集群的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
    
  3. 由此得出,pod的targetport在对于不同的pod的情况下是可以重复的;nodeport如果是处于同一个节点是不能重复的;clusterip在clusterip的地址不同(也就是iptables和ipvs的规则中不冲突/或者简单理解为不同服务)的情况下是可以重复的

参考链接: https://xuxinkun.github.io/2016/07/22/kubernetes-proxy/