TKE & Ingress-Nginx Controller 之客户端 IP
项目中使用腾讯云的 TKE 部署 Spring Boot 应用,但是应用中获取到的客户端 IP 是 TKE 节点的云服务器的内网 IP(有时候是一个不知道哪来的内网 IP,怀疑是 CLB 的内网 IP),而不是客户端的真实 IP。
为了查明是哪一个环节的问题,需要查看对应的日志。
CLB 貌似是仅支持对七层的监听器记录访问日志。Ingress-Nginx Controller 使用的是 L4 转发,启用了日志服务后也确实没有看到日志。
TKE 的 Ingress-Nginx Controller 默认的日志格式保存在对应的 ConfigMap 的 log-format-upstream
中,其内容如下:
$remote_addr - $remote_user [$time_iso8601] $msec "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $request_length $request_time [$proxy_upstream_name] [$proxy_alternative_upstream_name] [$upstream_addr] [$upstream_response_length] [$upstream_response_time] [$upstream_status] $req_id
为了查看 Ingress-Nginx Controller 接收到的请求头中的客户端 IP 地址,在上面的日志格式后面加上 $http_x_forwarded_for
即可。
查看 Ingress-Nginx Controller 的日志(Pod 中的 /var/log/nginx/nginx_access.log
文件),可以发现 $http_x_forwarded_for
确实是客户端的真实 IP。这说明 CLB 本身的转发没有问题。
tail -fn 100 /var/log/nginx/nginx_access.log
查看 Ingress-Nginx Controller 的 nginx.conf 文件(/etc/nginx/nginx.conf
),可以看到如下配置:
proxy_set_header X-Request-ID $req_id;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
# Pass the original X-Forwarded-For
proxy_set_header X-Original-Forwarded-For $http_x_forwarded_for;
其中 X-Real-IP
和 X-Forwarded-For
都被设置为 $remote_addr
(这里按说应该是 CLB 的 内网 IP,但不知道为什么有时候会是 TKE 节点的内网 IP),而实际的客户端 IP $http_x_forwarded_for
被设置到了一个自定义的 Header X-Original-Forwarded-For
上。如果应用能获取到这个自定义的 Header 也可以,但不知道为什么应用这边的 Request 中没有看到这个 Header。
最后还是在 官网文档 中找到了解决办法:启用 PROXY protocol。
Question - How to obtain the real-client-ipaddress ?
The goto solution for retaining the real-client IPaddress is to enable PROXY protocol.
Enabling PROXY protocol has to be done on both, the Ingress NGINX controller, as well as the L4 load balancer, in front of the controller.
The real-client IP address is lost by default, when traffic is forwarded over the network. But enabling PROXY protocol ensures that the connection details are retained and hence the real-client IP address doesn't get lost.
Enabling proxy-protocol on the controller is documented here .
For enabling proxy-protocol on the LoadBalancer, please refer to the documentation of your infrastructure provider because that is where the LB is provisioned.
Some more info available here
Some more info on proxy-protocol is here
对于 Ingress-Nginx Controller 来说只需要在 ConfigMap 添加如下配置即可:
apiVersion: v1
data:
enable-real-ip: "true"
use-proxy-protocol: "true"
kind: ConfigMap
同时,L4 负载均衡器上也需要开启 PROXY protocol,否则会导致所有请求都失败。
CLB 开启 ProxyProtocol 配置需要先提工单开通[1],而且传统账号需要先升级为标准账号[2]。之后就可以在监听器的编辑页面的高级选项中看到该配置项了。
注意
- 由于两边需要分别配置,请求会有短暂的中断,建议在流量较小的时候进行配置。
虽然页面上有提示“不支持在线平滑迁移”,但这边实际操作的时候,两边(CLB 和 Ingress-Nginx Controller)修改配置后几乎都是立即就生效了。 - TKE 不再支持创建新的 Ingress-Nginx Controller 实例[3]。