使用k8s暴露我们的服务给外部访问的方式主要是有2种,一种就是nodeport类型,还有一种就是LoadBalancer,通常这2中都会做一个负载均衡,但是有一个问题就是服务端可能无法获取到客户端的真实ip,service.spec.externalTrafficPolicy这个字段就帮您解决了这个问题。
service.spec.externalTrafficPolicy - 表示此服务是否希望将外部流量路由到节点本地或集群范围的端点。 有两个可用选项:Cluster(默认)和 Local。 Cluster 隐藏了客户端源 IP,可能导致第二跳到另一个节点,但具有良好的整体负载分布。 Local 保留客户端源 IP 并避免 LoadBalancer 和 NodePort 类型服务的第二跳, 但存在潜在的不均衡流量传播风险。
externalTrafficPolicy存在2种模式,一种是默认的Cluster类型,一种是Local类型,Cluster类型就是service基本的模式负载均衡,今天我们来讲一下Local这种模式,为什么Local模式会出现负载不均衡。
首先我们创建一个externalTrafficPolicy为Cluster类型的service,大家都知道k8s中的网络策略都是通过kube-proxy来配置iptables规则来进行转发的,下面我们查看下externalTrafficPolicy为Cluster类型的service对应nodeport的iptables规则
1 2 3 4 5 6 7 8 9 10 [root@VM-0 -3 -centos ~]# kubectl get svc -n testNAME TYPE CLUSTER -IP EXTERNAL -IP PORT(S) AGE go-test ClusterIP 172.16 .46 .161 <none > 80 /TCP 4 d16h nginx ClusterIP 172.16 .45 .116 <none > 80 /TCP 7 d21h nginx-externaltrafficpolicy NodePort 172.16 .22 .159 <none > 80 :31015 /TCP 15 h nginx-log LoadBalancer 172.16 .96 .7 106.55 .216 .XX 80 :31465 /TCP 3 d springboot ClusterIP 172.16 .77 .157 <none > 8080 /TCP 4 d [root@VM-0 -3 -centos ~]# iptables-save | grep 31465 -A KUBE-NODEPORTS -p tcp -m comment -A KUBE-NODEPORTS -p tcp -m comment
我们nignx-log这个service就是Cluster类型,我们发现节点上对应31465这个nodeport的iptables规则就是放通所有来源ip来进行访问这个端口。
下面我们再看看Local类型的service,对应的iptables规则是什么样,这里我们nginx-externaltrafficpolicy这个service就是Local类型,对应service的yaml文件如下。
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 apiVersion: v1kind: Servicemetadata: annotations: service.cloud.tencent.com/local-svc-weighted-balance: "false" service.kubernetes.io/local-svc-only-bind-node-with-pod: "false" creationTimestamp: "2020-11-26T10:11:47Z" managedFields: - apiVersion: v1 manager: tke-apiserver operation: Update time: "2020-11-26T10:11:47Z" name: nginx-externaltrafficpolicy namespace: test resourceVersion: "2118736256" selfLink: /api/ v1/namespaces/ test/services/ nginx-externaltrafficpolicy uid: 7255 ae77-0 d6c-45 da-8171 -60521535 d020spec: clusterIP: 172.16 .22 .159 externalTrafficPolicy: Local ports: - name: 80 -80 -tcp nodePort: 31015 port: 80 protocol: TCP targetPort: 80 selector: k8s-app: nginx-externaltrafficpolicy qcloud-app: nginx-externaltrafficpolicy sessionAffinity: None type: NodePortstatus: loadBalancer: { }
1 2 3 4 5 [root @VM-0-3-centos ~]nginx-externaltrafficpolicy NodePort 172 .16 .22 .159 <none > 80:31015/ TCP 16h [root @VM-0-3-centos ~] -A KUBE-NODEPORTS -s 127 .0 .0 .0 /8 -p tcp -m comment --comment "test/nginx-externaltrafficpolicy:80-80-tcp" -m tcp --dport 31015 -j KUBE-MARK-MASQ -A KUBE-NODEPORTS -p tcp -m comment --comment "test/nginx-externaltrafficpolicy:80-80-tcp" -m tcp --dport 31015 -j KUBE-XLB-3LS5F4HE6J2O753K
:KUBE-MARK-MASQ - [0:0] /对于符合条件的包 set mark 0x4000, 有此标记的数据包会在KUBE-POSTROUTING chain中统一做MASQUERADE /
对于KUBE-MARK-MASQ链中所有规则设置了kubernetes独有MARK标记,在KUBE-POSTROUTING链中对NODE节点上匹配kubernetes独有MARK标记的数据包,进行SNAT处理。
查看节点上nginx-externaltrafficpolicy的nodeport端口的iptables规则,细心的你肯定发现有个地方和Cluster类型的是不一样的,那就是第一条规则中加了一个源ip网段的访问限制,默认只有127.0.0.0/8才能访问这个,那么Local模式的原理这里就清楚了,其实就是这个iptables规则配置的源ip导致的。
这也就是为啥你访问对应的nodeport的时候,只有pod所在的节点才能访问通,我们在同一个vpc下非集群节点进行访问nginx-externaltrafficpolicy这个pod测试一下
1 2 [root@VM-0 -3 -centos ~]# kubectl get pod -n test -o wide | grep nginx-externaltrafficpolicy-6654865 c87-25 cnq nginx-externaltrafficpolicy-6654865 c87-25 cnq 2/2 Running 0 16h 10.0.2.37 10.0.0.3 <none> 1/1
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 [root@VM-0-13-centos ~]# curl 10.0.0.3:31015<!DOCTYPE html > <html > <head > <title > Welcome to nginx!</title > <style > body { width : 35em ; margin : 0 auto; font-family : Tahoma, Verdana, Arial, sans-serif; } </style > </head > <body > <h1 > Welcome to nginx!</h1 > <p > If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p > <p > For online documentation and support please refer to<a href ="http://nginx.org/" > nginx.org</a > .<br /> Commercial support is available at<a href ="http://nginx.com/" > nginx.com</a > .</p > <p > <em > Thank you for using nginx.</em > </p > </body > </html > [root@VM-0-13-centos ~]# curl 10.0.0.10:31015
我们发现nginx-externaltrafficpolicy这个pod部署在10.0.0.3这个node上,我们在10.0.0.13这个节点访问nodeport,只有10.0.0.3这个节点的31015这个nodeport可以通,这也是符合Local模式的。
有的时候我们在定位问题也可以注意一下这个配置,可能出现只能访问pod所在节点才能通,这里可以检查下这个配置是否配置成了Local。