如何使Kubernetes Nginx Ingress结合AWS ELB实现WebSocket正常运行?
我之前处理过几乎一模一样的生产配置场景,你的问题核心是WebSocket升级请求被代理层拦截、代理头传递不完整,再加上TCP模式下的重定向逻辑冲突导致的。下面是一步步的修复方案:
1. 修正ELB控制器服务的配置错误
首先你的注解里有个小笔误(ssl-cert后面多了一个冒号),这会直接导致SSL证书配置失效,先修正这个:
service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:iam::xxx:server-certificate/staging
然后保持ELB的SSL终止模式(后端用HTTP协议),同时补充代理头传递的配置,确保Ingress能正确识别请求协议:
service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http service.beta.kubernetes.io/aws-load-balancer-proxy-protocol: '*' service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:iam::xxx:server-certificate/staging service.beta.kubernetes.io/aws-load-balancer-ssl-ports: https # 新增:让ELB传递协议和客户端IP头,解决重定向和来源识别问题 service.beta.kubernetes.io/aws-load-balancer-x-forwarded-proto: "true" service.beta.kubernetes.io/aws-load-balancer-x-forwarded-for: "true"
2. 更新Ingress注解以支持WebSocket
Nginx Ingress默认不会自动处理WebSocket的Upgrade请求,需要添加专门的注解来配置头转发和指定WebSocket服务:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: # 保留你已有的CORS配置 nginx.ingress.kubernetes.io/cors-allow-methods: "PUT, GET, POST, OPTIONS" nginx.ingress.kubernetes.io/cors-allow-headers: "DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type" nginx.ingress.kubernetes.io/cors-allow-origin: "*" nginx.ingress.kubernetes.io/cors-allow-credentials: "true" nginx.ingress.kubernetes.io/service-upstream: true # 保留强制HTTPS重定向,但依赖ELB传递的X-Forwarded-Proto头来判断 nginx.ingress.kubernetes.io/force-ssl-redirect: "true" # 新增WebSocket核心配置 # 替换成你的Rails服务名称,指定处理WebSocket请求的后端服务 nginx.ingress.kubernetes.io/websocket-services: "your-rails-app-service" # 配置Nginx转发WebSocket升级所需的头和HTTP版本 nginx.ingress.kubernetes.io/configuration-snippet: | proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_http_version 1.1; # 可选:增加超时时间,避免WebSocket连接被Nginx过早断开 proxy_connect_timeout 7d; proxy_send_timeout 7d; proxy_read_timeout 7d;
3. 调整Rails应用的代理信任配置
因为流量经过ELB和Ingress两层代理,Rails需要信任这些代理才能正确识别WebSocket请求的来源和协议:
在config/environments/production.rb(或对应环境配置文件)中添加:
# 信任代理集群的IP(如果集群IP范围固定,建议用具体CIDR更安全) config.action_dispatch.trusted_proxies = %w(0.0.0.0/0) # 配置ActionCable(如果你用的是Rails自带的WebSocket服务) config.action_cable.allowed_request_origins = [/https?:\/\/your-domain\.com/] config.action_cable.url = "wss://your-domain.com/cable"
4. 为什么TCP模式会导致无限重定向?
当你把ELB改成TCP模式时,ELB不再终止SSL,而是直接把原始TCP流量转发到Ingress的80端口。此时Ingress检测到请求是HTTP(因为收到的是未加密流量),触发force-ssl-redirect重定向到HTTPS,但ELB又把这个HTTPS请求转发到Ingress的80端口,形成死循环。所以保持ELB的SSL终止模式才是正确的选择。
完成以上调整后,重启Ingress控制器和Rails应用,用浏览器开发者工具检查WebSocket请求:确认Upgrade: websocket和Connection: upgrade头被正确传递,并且返回状态码101,就说明配置生效了。
内容的提问来源于stack exchange,提问作者slashRahul




