如何在kubernetes集群中获取客户端真实ip地址
如何在kubernetes集群中使用gin和vue获取客户端真实ip地址
背景:
最近用golang gin框架和vue框架做了一个应用,这个应用的用途是通过获取到客户端ip然后返回具体位置。整个应用部署在自建的kubernetes集群上。这个应用使用vue做前端,使用gin做后端,版本为: gin 1.7.7 和 vue 2.6.11
gin通过将编译好的二进制文件构建到alpine镜像中,构建好后端应用镜像然后进行deployment部署,并设置了service ClusterIP
vue也是通过编译好的dist等前端文件构建到nginx镜像中,构建好的前端应用镜像然后进行deployment部署,以service NodePort方式进行对外暴露端口。(这里需要你给nginx写好配置反向代理文件,指定后端的ClusterIP及端口)
我的k8s集群中我没有用到ingress,只是用到了service Nodeport或ClusterIP。
最后可以从前端访问到后端,唯一的问题是gin获取到的客户端ip不对。
第一: 可能是gin版本问题
发现在go中国的csdn中有一篇文章说,“石墨文档某 HTTP 服务升级 Gin 框架到 1.7.2 后突然发现一个 『Bug』,升级后服务端无法获正确的客户端 IP” ,而我的gin版本确实是1.7之后,于是通读全文,并在github上面阅读两个版本的源码,对比其差异。如下参考资料 1
我的gin里面还是继续使用 c.ClientIP()来进行获取客户端ip地址。
第二: 可能是k8s的问题
现象是从后台的gin中总是获取到容器的ip地址,而不是客户端的ip地址,具体是由于k8s的各个节点对请求进行了转发导致,于是对前端暴露的Service Nodeport进行补丁:
kubectl patch svc mySvcName -p '{"spec":{"externalTrafficPolicy":"Local"}}'
假设你的deployment的replicas为1,并且有6台节点(192.168.1.2-192.168.1.7),你的前端pod假设在节点192.168.1.6上运行(kubectl describe pod podName),暴露在31872端口上(kubectl get svc),那么你只能在浏览器中使用此节点的ip和暴露出的端口31872进行访问,而使用其他ip(192.168.1.2,192.168.1.3,192.168.1.4,192.168.1.5,192.168.1.7)是无法访问的。
例如:有6台虚拟机节点,分为 3台主节点(master)和3台工作节点(worker),而192.168.1.1为网关路由器地址,所以从2开始,2-4为master,5-7为worker
192.168.1.2/192.168.1.3/192.168.1.4/192.168.1.5/192.168.1.6/192.168.1.7
假设你的pod在192.168.1.6上运行,此时你只能通过192.168.1.6:31872,无法使用其他ip进行访问。
这里有一个坑点: 就是当你删除或者重启这个deployment或pod,会发生此pod漂移到其他节点上运行,假设漂移到192.168.1.2,那么你对外部的访问链接也就得改变。
以前访问192.168.1.6:31872即可以访问前端,但是漂移后这个192.168.1.6:31872将无法使用,只能找这个pod的所在地址进行访问(192.168.1.2:31872)。
假设你的业务场景一直想使用一个固定的ip和port进行访问前端应用,那么就需要修改deployment yaml和serviceNodeport yaml
deployment yaml :
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
nodeName: node5
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
192.168.1.6 的nodeName是 node5 ,我们将这个pod固定到某个节点上,这样前端应用的ip地址就不会变化了。
serviceNodeport yaml:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
externalTrafficPolicy: Local
type: NodePort
selector:
app: nginx
ports:
- port: 80
targetPort: 80
nodePort: 31872
请注意上图中这里写了NodePort 31872,这里写了定值,下次重新删除service再apply也不会改变serviceNodePort端口号了,并且也对流量进行本地处理。
综上,以后再重启甚至删除重建deployment或pod,或serviceNodeport,都不会导致你的前端应用的ip和port有任何变化,业务人员可以一直使用固定ip和端口进行访问。
参考资料:
1. https://blog.csdn.net/RA681t58CJxsgCkJ31/article/details/120426004
2. https://kubernetes.io/zh-cn/docs/tutorials/services/source-ip/
3. https://kubernetes.io/zh-cn/docs/tasks/configure-pod-container/assign-pods-nodes/
更多推荐
所有评论(0)