Atlantis
GitHub Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

4. 来源IP测试

1. 前言

之前有原先使用物理机跑业务的客户需要做业务容器化上私有云,他们对网络请求的来源IP和端口会做校验(客户使用 UDP 协议),迁移进容器集群后产生了比较多问题。当时组长正好在客户现场做培训,于是交代我写个材料方便给客户做解答,这里就以使用 Flannel 网络插件,kube-proxy 启用 IPVS 的前提条件下,验证常见使用场景下的来源 IP。

2. 容器网络

服务端 nginx-test 运行一个 nginx 进程监听 80 端口,配置 Service 并开启 NodePort 进行测试。

2.1 集群内Pod互访

在服务端 Pod 可以看到源 Pod 的 IP 和端口:

alt text

alt text

alt text

2.2 集群内Pod通过Service访问Pod

在服务端 Pod 可以看到客户端 Pod 的 IP 和端口:

alt text

alt text

alt text

alt text

2.3 集群外使用<EIP:NodePort>通过Service访问Pod

externalTrafficPolicy 默认为 Cluster,每个节点都可以转发请求,由于经过 NAT 转发,这种情况下无法获取到来源 IP

alt text

alt text

alt text

alt text

externalTrafficPolicy 修改为 Local 后,只有 Pod 所在节点都可以转发请求,这种情况下可以获取到来源 IP,缺点是需要固定 Pod 宿主机

alt text

alt text

alt text

alt text

3. hostNetwork

服务端 nginx-test 切换网络模式为 hostNetwork,使用宿主机网络

3.1 集群内Pod互访

跨网段访问,会产生 NAT,服务端看到的是客户端 Pod 所在宿主机的 IP:

alt text

alt text

alt text

3.2 集群内Pod访问Service

请求可以经过 Service 转发到后端,由于依然存在 NAT,服务端看到的是客户端 Pod 所在宿主机的 IP

alt text

alt text

alt text

alt text

3.3 集群外通过<EIP:NodePort>访问Pod

externalTrafficPolicy 为 Cluster 时,和使用集群网络时稍有不同

alt text

若访问<Pod宿主机EIP:NodePort>,可以获取到来源IP

alt text

访问<其他宿主机EIP:NodePort>,无法获取到来源IP

alt text

alt text

externalTrafficPolicy 修改为 Local 后,只有 Pod 所在节点都可以转发请求,这种情况下可以获取到来源 IP

alt text

alt text

alt text

3.4 集群外通过<EIP:Pod端口>访问Pod

使用宿主机网络时,Pod 的端口占用宿主机的端口,因此也可以直接访问到

alt text

alt text

alt text

3.5 hostNetwork模式的Pod访问外部服务

hostNetwork 模式下 Pod 使用的是宿主机网络,不存在 NAT 转换,使用宿主机的 IP 和端口

alt text

alt text

alt text

alt text

4. UDP

UDP 与 TCP 的情况相同,遇到需要 NAT 转换的场景,无论入向和出向,IP 与端口都会发生变化

alt text

alt text

5. Ingress

以使用 nginx-ingress-controller 为例,对 nginx 本身来说,它所看到的来源 IP 与上面的叙述一致,那经过 nginx 转发的请求对接收者来说会是什么情况?

这里使用 ingress 暴露一个集群中的 prometheus,进入容器查看生成的 nginx 配置文件如下,可以看到每一个域名都有一个对应的配置:

alt text

upstream 统一为 upstream_balancer

alt text

实际上发往 upstream 的请求都会被 lua 处理,0.0.0.0:1234 只是一个占位配置:

alt text

查看连接会发现请求直接转发到了 Pod,而不是 Service:

alt text

nginx-ingress-controller 也具备负载均衡的功能(默认 RoundRobin),它从 kube-apiserver 同步 service 及关联的 endpoint,若接收到匹配 ingress 设置的请求,就直接转发给后端 Pod

因此可以得出结论,使用ingress暴露服务后:

  1. 后端的 Pod 在四层接收到的来源 IP 固定为 ingress-controller 的 Pod IP
  2. 后端的 Pod 在七层读取到的客户端 IP(ClientIP)取决于用户如何访问 ingress-controller,如果是用 nodePort 访问,能读取到来源 IP,如果是使用 LB 访问,需要在应用层添加信息,最外层的 LB 将来源 IP 添加到请求头部并传递给 ingress-controller,再传递给后端 Pod