【问题标题】:GKE Node.JS app: Error during WebSocket handshakeGKE Node.JS 应用程序:WebSocket 握手期间出错
【发布时间】:2020-10-28 21:56:00
【问题描述】:

我对 Google Kubernetes Engine 还是很陌生,一般来说只是 Kubernetes。 我创建了一个“生产型”Kubernetes 集群,运行我使用 socket.io 的旧 Node.js 应用程序。为了帮助自己做到这一点,我使用了 Google 的 "Deploying a containerized web application" how-to,之后我设置了一个带有 Ingress 的负载均衡器,它通过遵循另一个指南 Using Google-managed SSL certificates (the Setting up the managed certificate part) 来使用托管证书。这给我留下了一个使用 1 个池和三个实例组的集群,每个实例组使用 1-2 个节点。

后端已启动,并且前端能够正确连接到它。问题在于 WebSockets 和前端收到错误 WebSocket connection to 'wss://mycooldomain.com/socket.io/?EIO=3&transport=websocket&sid=afskjaisfhf-afasfoiaofis' failed: Error during WebSocket handshake: Unexpected response code: 400,我整天都在试图弄清楚。

我一直在使用的两个指南中的后者提到创建节点端口和托管证书,然后是一个将两者链接在一起的入口。我决定为负载均衡器创建一个具有不同后端配置的 Ingress 以解决问题:

apiVersion: cloud.google.com/v1beta1
kind: BackendConfig
metadata:
  name: my-cool-backendconfig
  namespace: my-cool-namespace
spec:
  timeoutSec: 60
  connectionDraining:
    drainingTimeoutSec: 30
  sessionAffinity:
    affinityType: "CLIENT_IP"

创建它的原因是尝试不同的超时值以保持 WebSocket 连接。我也尝试过timeoutSec: 20000drainingTimeoutSec: 3000 等值。 sessionAffinity 部分也来自许多 StackOverflow 线程和 GitHub 问题。

所以必须在我的 NodePort 上应用该配置:

apiVersion: v1
kind: Service
metadata:
  namespace: my-cool-namespace
  name: my-cool-nodeport
  labels:
    app: my-cool-app
  annotations:
    cloud.google.com/backend-config: '{"ports": {"80":"my-cool-backendconfig"}}'
spec:
  selector:
    app: my-cool-app
  type: NodePort
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080

如果我理解正确,在我的 Ingress 上:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  namespace: my-cool-namespace
  name: my-cool-ingress
  annotations:
    kubernetes.io/ingress.global-static-ip-name: my-cool-global-ip
    networking.gke.io/managed-certificates: my-cool-certificate
    cloud.google.com/backend-config: '{"default": "my-cool-backendconfig"}'
spec:
  backend:
    serviceName: my-cool-nodeport
    servicePort: 80

在尝试了不同的超时值后,我注意到Error during WebSocket handshake: Unexpected response code: 400 错误不一定会发生在每个socket.emit() 上,而且相当多变,这取决于我猜负载平衡器是否允许连接(?) .

即使 Google 指导 mention 使用更大的超时值,即使是最淫秽的(timeoutSec: 20000 如上所述)也无助于建立稳定的 WebSocket 连接,因为它们最终偶尔会抛出错误。

从后端/前端节点应用程序的角度来看问题,我只是更改了 socket.io 配置以尝试在 polling 之前先建立 websocket 连接:

const server = http.createServer(app);
const io = require('socket.io').listen(server);
io.set('transports', ['websocket', 'polling']);

这也没有帮助。

如何让它工作而不时不时抛出错误?

额外问题:我注意到很多有相同/类似问题的用户都使用 Nginx Ingress 控制器,这对于适当的负载平衡来说是必要的,还是仅适用于实际生产环境?

【问题讨论】:

  • 您使用的是什么 GKE 版本。你能分享你的整个 Socket.io 配置吗?
  • @PjoterS 我在1.16.13-gke.401。我的 socket.io 没有太多配置。前端和后端都将websocket 指定为polling 之前的第一个传输,仅此而已。前端连接到www.mycooldomain.com(这是一个示例,顺便说一句,我有一个与我自己不同的域,并且正确配置了 DNS),没有指定端口。顺便说一句,我的前端使用ngx-socket-io

标签: kubernetes websocket socket.io load-balancing google-kubernetes-engine


【解决方案1】:

如果它仅在某些情况下不起作用,这可能是由于您正在失去会话亲和性。 For starters, read into session affinity docs。根据您所说的,由于您有多个节点,您可能会丢失它。尝试缩小到一个节点,看看会发生什么。如果同样的问题仍然存在,请检查每个节点中有多少副本,尝试将副本减少到每个节点一个 - 也许您在副本级别失去了会话亲和性。如果每个节点保留一个副本,您可能能够扩大规模。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-09
    • 1970-01-01
    相关资源
    最近更新 更多