我在运行 NGINX 的自托管服务器上有一个带有外部负载均衡器的 Kubernetes 集群。我尝试激活proxy_protocol
以获取real_ip
客户端,但 NGINX 日志
2020/05/11 14:57:54 [error] 29614#29614: *1325 broken header: "▒▒▒▒▒▒▒Ωߑa"5▒li<c▒*▒ ▒▒▒s▒ ▒6▒▒▒▒▒X▒▒o▒▒▒E▒▒i▒{ ▒/▒0▒+▒,̨̩▒▒ ▒▒
▒▒/5▒" while reading PROXY protocol, client: 51.178.168.233, server: 0.0.0.0:443
这是我的 NGINX 配置文件:
worker_processes 4;
worker_rlimit_nofile 40000;
events {
worker_connections 8192;
}
stream {
upstream rancher_servers_http {
least_conn;
server <IP_NODE_1>:80 max_fails=3 fail_timeout=5s;
server <IP_NODE_2>:80 max_fails=3 fail_timeout=5s;
server <IP_NODE_3>:80 max_fails=3 fail_timeout=5s;
}
server {
listen 80;
proxy_protocol on;
proxy_pass rancher_servers_http;
}
upstream rancher_servers_https {
least_conn;
server <IP_NODE_1>:443 max_fails=3 fail_timeout=5s;
server <IP_NODE_2>:443 max_fails=3 fail_timeout=5s;
server <IP_NODE_3>:443 max_fails=3 fail_timeout=5s;
}
server {
listen 443 ssl proxy_protocol;
ssl_certificate /certs/fullchain.pem;
ssl_certificate_key /certs/privkey.pem;
proxy_pass rancher_servers_https;
proxy_protocol on;
}
}
这是我的configmap
入口控制器:
apiVersion: v1
data:
compute-full-forwarded-for: "true"
proxy-body-size: 500M
proxy-protocol: "true"
use-forwarded-headers: "true"
kind: ConfigMap
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: '{"apiVersion":"v1","data":null,"kind":"ConfigMap","metadata":{"annotations":{},"labels":{"app":"ingress-nginx"},"name":"nginx-configuration","namespace":"ingress-nginx"}}'
creationTimestamp: "2019-12-09T13:26:59Z"
labels:
app: ingress-nginx
name: nginx-configuration
namespace: ingress-nginx
在我添加指令之前一切都运行正常proxy_protocol
,但是现在我收到了所有这些broken headers
错误,并且我无法访问入口后面的任何服务而不会出现错误connection reset
。
我的配置可能有什么问题?
我应该使用 http 反向代理而不是 tcp 反向代理吗?
谢谢。
编辑:
我还应该说我的集群中没有任何类型的服务LoadBalancer
。我应该有一个吗?我正在考虑 Metallb,但我不确定它会给我的配置添加什么,因为我已经使用 nginx 对节点进行负载平衡。
答案1
Nginx 允许您指定在传入或传出请求中是否使用 proxy_protocol,并且您会混淆这两者。
在以下位置使用 proxy_protocol传入连接,你必须像这样添加行proxy_protocol
:listen
listen 443 ssl proxy_protocol;
在以下位置使用 proxy_protocol传出连接,您必须使用独立proxy_protocol
指令,如下所示:
proxy_protocol on;
他们是不是相同。在负载均衡器中,传入连接来自浏览器,浏览器不支持代理协议。您只需要在传出请求中使用代理协议,发送到 kubernetes 集群中的 nginx-ingress。
因此,从指令proxy_protocol
中删除该参数listen
,它就应该可以工作了。
此外,你还需要在use-forwarded-headers: "false"
nginx-ingress 配置中。这控制是否在X-Forwarded-For
传入连接(从 nginx-ingress 的角度来看,即传出来自负载均衡器),并且您在这些中使用代理协议而不是标头。启用此功能后,您的用户可能能够通过指定 X-Forwarded-For 来欺骗 IP,这可能是一个安全问题。(仅当 nginx-ingress 优先考虑标头而不是代理协议时,我不确定)
另外:nginx-ingress 本身已经在所有 pod 之间平衡了流量负载。在您的架构中,您正在运行两层负载均衡器,这可能是不必要的。如果您想简化,请强制 nginx-ingress 在单个节点上运行(例如nodeSelector
),然后将所有流量发送到该节点。如果您想将负载均衡器保留在专用机器上,您可以将第 4 台机器加入集群并确保它只运行 nginx-ingress(带有污点和容忍度)。
另外,请确保你正在使用 hostNetwork: true 运行 nginx-ingress,否则你可能会遇到完后还有平衡层(kube-proxy,kubernetes 服务代理)