一、直接访问情况

针对没有使用Istio的情况(需要关闭Istio),没有任何代理,客户端直接使用端口映射或者网关等方式访问后端服务。

1、Service的类型为NodePort:

把相应的Service的externalTrafficPolicy改为Local,默认为Cluster。但是需要使用pod所在节点的ip进行访问,不能使用集群中其他的ip(设置 service.spec.externalTrafficPolicy 为 Local 会将请求代理到本地端点,不将流量转发到其他节点,从而保留原始IP地址。)。

在Kubernetes 的 Service 对 externalTrafficPolicy 设置,以及和获取客户端IP相关知识点 | 码农网

http://www.voidcn.com/article/p-fxejirdw-bym.html

在Kubernetes 的 Service 对 externalTrafficPolicy 设置,以及和获取客户端IP相关知识点 | 码农网

如此就能使用request.getRemoteAddress()获取客户端真实ip

2、Service类型为ClusterIP

由于需要做source nat,直接获取到的不是客户端的真实ip

二、使用Nginx做反向代理

上面的方式已经尝试过可行。但是有明显的缺陷。

实际使用中,一般会在service前面加一个高可用负载均衡(比如Nginx+Keepalived),然后再Nginx中配置将真实IP放到请求头,代码中通过请求头获取,Nginx的配置如下:

server {
  # 在每一个 location 配置里都需要
  location / {
    # host 修改为真实的域名和端口
    proxy_set_header Host $http_host;
    # 客户端真实ip
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    # 客户端真实协议(http/https)
    proxy_set_header X-Forwarded-Proto $scheme;
  }
}

如此,可以在使用request.getHeader("X-Real-IP")获取。

但是,如果Nginx是通过Docker容器启动的,那么获取到的时容器的ip地址, 127.17.0.1这样的ip地址,这个ip地址时docker0网桥的地址,不是客户端的真实ip。这时,需要使用host模式启动nginx,比如:

docker run --network=host --rm --name mynginx --volume /root/nginx-docker-demo/html/:/usr/share/nginx/html -d nginx:latest

注意--network=host。此时,如果使用了-p进行端口映射,将会被忽略,因为指定了hostNetWork=true,那么所有容器的端口将会直接映射到物理机上,容器的containerPort与hostPort必须一致。见《Kubernetes权威指南》P292。

使用host模式启动Nginx后,再通过request.getHeader("X-Real-IP")就可以拿到真实的客户端ip了。

三、TCP的情形

使用PROXY Protocol。