Kubernetes 和 Socket.io 404 错误 - 在本地工作但在应用到 kubernetes 后不工作

Kubernetes and Socket.io 404 error - works locally but not after applying to kubernetes

提前为这么长的问题道歉,我只是想确保我涵盖了所有内容...

我有一个反应应用程序,它应该连接到我已部署到 kubernetes 的服务中 运行 的套接字。服务 运行s 并且工作正常。我可以毫无问题地发出请求,但我无法连接到同一服务中的 websocket 运行ning。

当我在本地 运行 服务并使用 locahost uri 时,我能够连接到 websocket。

我的快递服务的 server.ts 文件如下所示:

import "dotenv/config";
import * as packageJson from "./package.json"

import service from "./lib/service";
const io = require("socket.io");

const PORT = process.env.PORT;

const server = service.listen(PORT, () => {
  console.info(`Server up and running on ${PORT}...`);
  console.info(`Environment = ${process.env.NODE_ENV}...`);
  console.info(`Service Version = ${packageJson.version}...`);
});

export const socket = io(server, {
  cors: {
    origin: process.env.ACCESS_CONTROL_ALLOW_ORIGIN,
    methods: ["GET", "POST"]
  }
});

socket.on('connection', function(skt) {
  console.log('User Socket Connected');
  socket.on("disconnect", () => console.log(`${skt.id} User disconnected.`));
});

export default service;

当我运行这个的时候,PORT设置为8088,access-control-allow-origin设置为*。请注意,我正在使用部署到 Kubernetes 的 rabbitmq 集群,当我在本地 运行 时,它与 rabbit 连接的 uri 相同。 Rabbitmq 没有 运行 在我的本地机器上运行,所以我知道这不是我的 rabbit 部署的问题,一定是我在连接套接字时做错了。

当我在本地 运行 服务时,我可以通过以下方式在 React 应用程序中进行连接:

const io = require("socket.io-client");
const socket = io("ws://localhost:8088", { path: "/socket.io" });

我看到了“用户套接字已连接”消息,一切都如我所料。

不过,当我将服务部署到 Kubernetes 时,我在确定如何连接到套接字时遇到了一些问题。

我的 Kubernetes 服务:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  type: ClusterIP
  ports:
    - port: 80
      targetPort: 8088
  selector:
    app: my-service

我的部署:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-service
spec:
  replicas: 2
  selector:
    matchLabels:
      app: my-service
  template:
    metadata:
      labels:
        app: my-service
    spec:
      containers:
        - name: project
          image: my-private-registry.com
          ports:
            - containerPort: 8088
      imagePullSecrets:
        - name: mySecret

最后,我的入口:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-service-ingress
  annotations:
    kubernetes.io/ingress.class: nginx
    cert-manager.io/cluster-issuer: letsencrypt-prod
    nginx.ingress.kubernetes.io/enable-cors: "true" // Just added this to see if it helped
    nginx.ingress.kubernetes.io/cors-allow-origin: "*" // Just added this to see if it helped
    nginx.ingress.kubernetes.io/cors-allow-methods: PUT, GET, POST, OPTIONS, DELETE, PATCH // Just added this to see if it helped
spec:
  tls:
    - hosts:
        - my.host.com
      secretName: my-service-tls
  rules:
    - host: "my.host.com"
      http:
        paths:
          - pathType: Prefix
            path: "/project"
            backend:
              service:
                name: my-service
                port:
                  number: 80

我可以很好地连接到服务并获取数据,post 数据等。但是我无法连接到 websocket,我收到 404 或 cors 错误。

由于服务在 my.host.com/project 上 运行ning,我假设套接字位于相同的 uri。所以我尝试连接:

const socket = io("ws://my.host.com", { path: "/project/socket.io" });

并且还使用 wss://

const socket = io("wss://my.host.com", { path: "/project/socket.io" });

我在控制台中记录了一个错误:

socket.on("connect_error", (err) => {
  console.log(`connect_error due to ${err.message}`);
});

两者都导致

polling-xhr.js?d33e:198 GET https://my.host.com/project/?EIO=4&transport=polling&t=NjWQ8Tc 404
websocket.ts?25e3:14 connect_error due to xhr poll error

我已经尝试了以下所有方法并且 none 有效:

const socket = io("ws://my.host.com", { path: "/socket.io" });
const socket = io("wss://my.host.com", { path: "/socket.io" });
const socket = io("ws://my.host.com", { path: "/project" });
const socket = io("wss://my.host.com", { path: "/project" });
const socket = io("ws://my.host.com", { path: "/" });
const socket = io("wss://my.host.com", { path: "/" });
const socket = io("ws://my.host.com");
const socket = io("wss://my.host.com");

同样,这在本地服务 运行 时有效,所以我一定是遗漏了什么,非常感谢任何帮助。

有没有办法在 Kubernetes pod 上找到 rabbit 被广播到的位置?

万一以后有人偶然发现这个问题并想知道如何解决它,事实证明这对我来说是一个非常愚蠢的错误..

在:

export const socket = io(server, {
  cors: {
    origin: process.env.ACCESS_CONTROL_ALLOW_ORIGIN,
    methods: ["GET", "POST"]
  },
});

我只需要在套接字选项中添加 path: "/project/socket.io",这是有道理的。

然后,如果有人碰巧 运行 进入随后的问题,我在 post 到 websocket 轮询时收到 400 错误,所以我在 transports: [ "websocket" ] 中设置 socket.io-客户端选项,这似乎解决了它。插座现在可以工作了,我终于可以继续前进了!