如何在Python-Flask应用的K8s Pod中获取客户端公网IP?
我太懂你现在的困扰了——明明想拿到访问用户的真实公网IP,结果日志里清一色显示的都是Ingress控制器的IP。这其实是反向代理场景下的典型问题,咱们一步步拆解解决:
问题根源
当请求经Ingress控制器转发到你的Flask Pod时,控制器默认会作为中间代理,Flask收到的请求源IP自然就是控制器的IP,而非原始用户的公网IP。要拿到真实IP,得让Ingress主动传递客户端IP的头信息,同时Flask也要学会正确读取这些头。
解决方案步骤
1. 配置Ingress传递真实IP头
修改你的Ingress YAML,添加Nginx Ingress专属的注解,让控制器把真实客户端IP塞进X-Forwarded-For头里:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: your-ingress-name annotations: nginx.ingress.kubernetes.io/real-ip-header: "X-Forwarded-For" nginx.ingress.kubernetes.io/proxy-real-ip-cidr: "0.0.0.0/0" # 若知道Ingress控制器IP段,填进去更安全 spec: # 你的Ingress规则配置...
real-ip-header:告诉Ingress控制器从哪个HTTP头提取真实客户端IPproxy-real-ip-cidr:指定哪些IP属于可信代理范围,控制器会仅信任这些IP传递的头信息
2. 确认Service的externalTrafficPolicy设置
如果你的Ingress控制器用的是LoadBalancer类型Service,把externalTrafficPolicy设为Local能减少SNAT(源地址转换),最大程度保留原始客户端IP:
apiVersion: v1 kind: Service metadata: name: your-ingress-service spec: type: LoadBalancer externalTrafficPolicy: Local # 其他Service配置...
这个设置会让请求直接路由到运行Ingress控制器Pod的节点,避免节点间转发时替换源IP。
3. 在Flask应用中读取真实IP
Flask默认的request.remote_addr拿到的是代理(Ingress控制器)的IP,所以得从X-Forwarded-For头里提取真实IP。可以写个简单工具函数处理:
from flask import Flask, request app = Flask(__name__) def get_real_client_ip(): # X-Forwarded-For格式通常是 "客户端IP, 代理1IP, 代理2IP..." forwarded_for = request.headers.get('X-Forwarded-For') if forwarded_for: # 取第一个IP就是原始客户端的公网IP return forwarded_for.split(',')[0].strip() # 如果没有转发头, fallback到remote_addr return request.remote_addr @app.route('/') def index(): real_ip = get_real_client_ip() app.logger.info(f"Request from real IP: {real_ip}") return f"Your public IP is: {real_ip}" if __name__ == '__main__': app.run(host='0.0.0.0', port=5000)
4. 验证Ingress控制器的配置
有些Nginx Ingress Controller默认没开启转发头支持,得检查它的ConfigMap:
kubectl get configmap nginx-ingress-controller -n <你的Ingress命名空间> -o yaml
确保里面有use-forwarded-headers: "true"配置,要是没有就加上,然后重启Ingress控制器Pod生效:
kubectl rollout restart deployment nginx-ingress-controller -n <你的Ingress命名空间>
额外注意事项
如果你的Ingress前面还有一层负载均衡(比如云厂商LB、Cloudflare),X-Forwarded-For头里会包含多个IP,这时候要把上层负载均衡的IP段加到proxy-real-ip-cidr里,这样Ingress控制器才会把最外层的IP当作真实客户端IP。
内容的提问来源于stack exchange,提问作者Farkhod Sadykov

