我需要仅从当前节点上运行的pod配置kube代理到服务器,并避免连接在不同节点之间来回切换。
在文档中找到了一个解决方案:
从Kubernetes 1.5开始,发送到Type=NodePort的服务的数据包默认为源NAT。您可以通过创建NodePort服务来测试这一点:
$ kubectl expose deployment source-ip-app --name=nodeport --port=80 --target-port=8080 --type=NodePort
service/nodeport exposed
$ NODEPORT=$(kubectl get -o jsonpath="{.spec.ports[0].nodePort}" services nodeport)
$ NODES=$(kubectl get nodes -o jsonpath='{ $.items[*].status.addresses[?(@.type=="ExternalIP")].address }')
如果您在cloudprovider上运行,则可能需要为节点打开防火墙规则:上面报告的nodeport。现在,您可以尝试通过上面分配的节点端口从集群外部访问服务。
$ for node in $NODES; do curl -s $node:$NODEPORT | grep -i client_address; done
client_address=10.180.1.1
client_address=10.240.0.5
client_address=10.240.0.3
请注意,这些不是正确的客户端IP,它们是集群内部IP。发生的情况如下:客户端向node2:nodePort发送数据包node2将数据包中的源IP地址(SNAT(替换为其自己的IP地址node2将数据包上的目标IP替换为pod IP数据包路由到节点1,然后再路由到端点pod的回复被路由回node2吊舱的回复被发送回客户端
视觉:
client
^
v
node 1 <--- node 2
| ^ SNAT
| | --->
v |
endpoint
为了避免这种情况,Kubernetes有一个保留客户端源IP的功能(请在此处查看功能可用性(。将service.spec.externalTrafficPolicy设置为值Local只会将请求代理到本地端点,而不会将流量转发到其他节点,从而保留原始源IP地址。如果没有本地终结点,发送到节点的数据包将被丢弃,因此您可以在任何数据包处理规则中依赖正确的源ip,您可以应用数据包将其传递到终结点。设置service.spec.externalTrafficPolicy字段如下:
$ kubectl patch svc nodeport -p '{"spec":{"externalTrafficPolicy":"Local"}}'
service/nodeport patched
现在,重新运行测试:
$ for node in $NODES; do curl --connect-timeout 1 -s $node:$NODEPORT | grep -i client_address; done
client_address=104.132.1.79
请注意,您只从运行端点pod的一个节点得到一个具有正确客户端IP的回复。发生的情况如下:客户端将数据包发送到node2:nodePort,它没有任何端点数据包被丢弃客户端将数据包发送到node1:nodePort,它确实有端点node1使用正确的源IP 将数据包路由到端点
视觉:
client
^ /
/ /
/ v X
node 1 node 2
^ |
| |
| v
endpoint
参考文档,使用标志:
--bind-address 127.0.0.1
对于这个标志,您需要添加kube代理的运行脚本。对于systemd,它存储在这里:
/etc/systemd/system/kube-proxy.service
比重新启动kube代理的服务:
systemctl restart kube-proxy