4. 来源IP测试
之前有原先使用物理机跑业务的客户需要做业务容器化上私有云,他们对网络请求的来源IP和端口会做校验(客户使用 UDP 协议),迁移进容器集群后产生了比较多问题。当时组长正好在客户现场做培训,于是交代我写个材料方便给客户做解答,这里就以使用 Flannel 网络插件,kube-proxy 启用 IPVS 的前提条件下,验证常见使用场景下的来源 IP。
服务端 nginx-test 运行一个 nginx 进程监听 80 端口,配置 Service 并开启 NodePort 进行测试。
在服务端 Pod 可以看到源 Pod 的 IP 和端口:
在服务端 Pod 可以看到客户端 Pod 的 IP 和端口:
externalTrafficPolicy 默认为 Cluster,每个节点都可以转发请求,由于经过 NAT 转发,这种情况下无法获取到来源 IP
externalTrafficPolicy 修改为 Local 后,只有 Pod 所在节点都可以转发请求,这种情况下可以获取到来源 IP,缺点是需要固定 Pod 宿主机
服务端 nginx-test 切换网络模式为 hostNetwork,使用宿主机网络
跨网段访问,会产生 NAT,服务端看到的是客户端 Pod 所在宿主机的 IP:
请求可以经过 Service 转发到后端,由于依然存在 NAT,服务端看到的是客户端 Pod 所在宿主机的 IP
externalTrafficPolicy 为 Cluster 时,和使用集群网络时稍有不同
若访问<Pod宿主机EIP:NodePort>,可以获取到来源IP
访问<其他宿主机EIP:NodePort>,无法获取到来源IP
externalTrafficPolicy 修改为 Local 后,只有 Pod 所在节点都可以转发请求,这种情况下可以获取到来源 IP
使用宿主机网络时,Pod 的端口占用宿主机的端口,因此也可以直接访问到
hostNetwork 模式下 Pod 使用的是宿主机网络,不存在 NAT 转换,使用宿主机的 IP 和端口
UDP 与 TCP 的情况相同,遇到需要 NAT 转换的场景,无论入向和出向,IP 与端口都会发生变化
以使用 nginx-ingress-controller 为例,对 nginx 本身来说,它所看到的来源 IP 与上面的叙述一致,那经过 nginx 转发的请求对接收者来说会是什么情况?
这里使用 ingress 暴露一个集群中的 prometheus,进入容器查看生成的 nginx 配置文件如下,可以看到每一个域名都有一个对应的配置:
upstream 统一为 upstream_balancer
实际上发往 upstream 的请求都会被 lua 处理,0.0.0.0:1234 只是一个占位配置:
查看连接会发现请求直接转发到了 Pod,而不是 Service:
nginx-ingress-controller 也具备负载均衡的功能(默认 RoundRobin),它从 kube-apiserver 同步 service 及关联的 endpoint,若接收到匹配 ingress 设置的请求,就直接转发给后端 Pod
因此可以得出结论,使用ingress暴露服务后:
- 后端的 Pod 在四层接收到的来源 IP 固定为 ingress-controller 的 Pod IP
- 后端的 Pod 在七层读取到的客户端 IP(ClientIP)取决于用户如何访问 ingress-controller,如果是用 nodePort 访问,能读取到来源 IP,如果是使用 LB 访问,需要在应用层添加信息,最外层的 LB 将来源 IP 添加到请求头部并传递给 ingress-controller,再传递给后端 Pod