我有一个简单的 Node.js 聊天示例,它使用 socket.io。我已在本地使用 docker 容器测试了此部署,并且 Web 客户端成功连接到 websocket (socket.io)。当我尝试使用入口控制器将其部署在 Kubernetes 集群上时,问题就出现了。
我的问题是,在使用入口控制器时,socket.io 有什么特别需要的东西吗? 我收到的错误消息是
<<browser name>> Can't estabilish a connection to the server at ws://<<address>>/socket.io/EIO=3&transport=websocket
下面是
服务器端的简单实现
var io = socket(server);
io.on('connection', (socket)=>{
console.log('made socket connection')
socket.on('chat', (message)=>{
message:message.value
})
以下是客户:
var socket = io.connect("http://localhost:3002", {
upgrade: false,
transports: ['websocket'],
secure: True
});
我的
ingressyaml 文件看起来像这样
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ws-ingress
namespace: websocket-ns
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/websocket-services: "ws-service"
nginx.ingress.kubernetes.io/proxy-read-timeout: '3600'
nginx.ingress.kubernetes.io/proxy-send-timeout: '3600'
nginx.ingress.kubernetes.io/server-snippet: |
http {
server {
listen 3002;
location = / {
proxy_set_header Upgrade "websocket";
proxy_http_version 1.1;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
proxy_set_header Connection "upgrade";
proxy_cache_bypass $http_upgrade;
}
upstream nodes {
hash $remote_addr consistent;
server app01:3002;
}
}
spec:
rules:
- host: "$host_address"
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: ws-service
port:
number: 80
服务yaml:
apiVersion: v1
kind: Service
metadata:
name: ws-service
namespace: websocket-ns
labels:
app: ws-service
spec:
type: LoadBalancer
selector:
app: ws-app
ports:
- port: 80
protocol: TCP
targetPort: 3002
服务器部署文件:
apiVersion: apps/v1
kind: Deployment
metadata:
name: ws-app
namespace: websocket-ns
labels:
app: ws-app
spec:
replicas: 1
selector:
matchLabels:
app: ws-app
template:
metadata:
labels:
app: ws-app
spec:
containers:
- name: ws-app
image: themuchy/socketexample
ports:
- containerPort: 3002
name: ws-app
这个正在与一个合作
Nginx 本身会将 HTTP 请求升级为 WebSocket。您不必添加任何相同的注释。
Deployment
和
service
、
YAML
配置看起来不错,但请尝试删除注释 server-snippet
。这样交通流量就会像LB > ingress (Connection upgrade) > service > pods
我的头撞墙一整天了! 发现注释中的一行就解决了问题! 我通过将副本数减少到 1 来解决这个问题,然后它就起作用了,很快就发现整个问题是会话粘性!参见socket io多个节点
强大的线路是:nginx.ingress.kubernetes.io/upstream-hash-by: "$client_ip" 这是我的 Ingress 规则
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nodejs-app-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
nginx.ingress.kubernetes.io/use-regex: "true"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
##### solved ws socket.io session stickness #####
nginx.ingress.kubernetes.io/upstream-hash-by: "$client_ip"
spec:
ingressClassName: "nginx"
tls:
- hosts:
- example.com
- www.example.com
secretName: example-tls
rules:
- host: example.com
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: nodejs
port:
number: 5000
- host: www.example.com
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: nodejs
port:
number: 5000