socket.io 如何处理 docker 部署的多个实例?

Posted

技术标签:

【中文标题】socket.io 如何处理 docker 部署的多个实例?【英文标题】:How does socket.io work with multiple instances which were deployed by docker ? 【发布时间】:2019-12-25 07:29:19 【问题描述】:

我创建一个服务器并在其上绑定 socket.io

const express = require('express');
var io = require('socket.io');
var app = express();
app.get('/', (req, res) => 
   res.sendFile(__dirname + '/index.html');
)
var server = require('http').createServer(app);

io = io.listen(server);


io.on('connection', function(socket)
    console.log('user connected', socket.id)
    socket.on('chat message', function(msg)
    console.log(socket.id, 'message: ' + msg);
   );
);

server.listen(9999)

当我在 docker 上部署 1 个实例时没问题(我使用 docker swarm 和 docker stack), 而如果我设置部署副本

这是我的 compose.yml

version: '3'
services:
  web:
  image: socket:v2
  ports:
    - "5000:9999"
    command: node index.js
    deploy:
    replicas: 2

我遇到一些问题,当发送消息到服务器时, server1 显示已连接,并显示收到消息, 但下次我发送时,server2 显示收到消息

我怎样才能让它成为“我连接的服务器就是我发送消息的服务器”?

【问题讨论】:

我认为你需要应用和配置Sticky session,你可以阅读这个***.com/questions/10494431/… 【参考方案1】:

您可以使用jwilder/nginx-proxy。这是使用 docker-gen 的 Docker 容器的自动 Nginx 代理。

用法

运行它:

$ docker run -d -p 80:80 -v /var/run/docker.sock:/tmp/docker.sock:ro jwilder/nginx-proxy

然后使用环境变量 VIRTUAL_HOST=subdomain.youdomain.com 启动您想要代理的任何容器

$ docker run -e VIRTUAL_HOST=foo.bar.com 

被代理的容器必须暴露被代理的端口, 通过在他们的 Dockerfile 中使用 EXPOSE 指令或使用 docker run 或 docker create 的 --expose 标志。

如果您的 DNS 设置为将 foo.bar.com 转发到主机 运行 nginx-proxy,请求将被路由到一个容器 VIRTUAL_HOST env 变量集。

使用 Docker-compose 你可以试试这个例子

Docker 编写

version: '2'

services:
  nginx-proxy:
    image: jwilder/nginx-proxy
    ports:
      - "80:80"
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro

  whoami:
    image: jwilder/whoami
    environment:
      - VIRTUAL_HOST=whoami.local

这里的jwilder/whoami 将被jwilder/nginx-proxy 代理为指定的VIRTUAL_HOST

您可以阅读更多关于 jwilder/nginx-proxy here 和 here 的信息

另外,你可以查看docker-compose-scale-with-sticky-sessions

你可以查看上面的例子

docker-compose up

然后运行

curl -H "Host: whoami.local" localhost

您将在每个响应中看到一个容器 ID

现在,是时候扩大规模了

docker-compose scale whoami=3

现在查看来自不同容器的屏幕截图响应。

要使用粘性会话,您可以使用 tpcwang 的 fork,允许您在容器级别使用 IP_HASH 指令来启用粘性会话。

如果你对内置功能感兴趣,可以试试Implement persistent (sticky) sessions

您可以发布服务并配置代理以实现持久化 (粘性)会话使用:

Cookie IP 哈希

IP 哈希

以下示例显示了如何使用 客户端 IP 哈希。这不像 cookie 那样灵活或一致 但为某些无法使用 其他方法。使用 IP 散列时,将 Interlock 代理重新配置为 使用主机模式联网,因为默认的入口联网模式 使用 SNAT,它会隐藏客户端 IP 地址。

创建一个覆盖网络,以便隔离和安全的服务流量:

$> docker network create -d overlay demo

使用 cookie 创建服务以用于使用 IP 的粘性会话 散列:

$> docker service create \
    --name demo \
    --network demo \
    --detach=false \
    --replicas=5 \
    --label com.docker.lb.hosts=demo.local \
    --label com.docker.lb.port=8080 \
    --label com.docker.lb.ip_hash=true \
    --env METADATA="demo-sticky" \
    ehazlett/docker-demo

Interlock 检测服务何时可用并发布它。什么时候 任务正在运行并且代理服务已更新,应用程序正在运行 可通过http://demo.local 获得,并配置为使用粘性 会话:

【讨论】:

以上是关于socket.io 如何处理 docker 部署的多个实例?的主要内容,如果未能解决你的问题,请参考以下文章

socket.io:如何处理 4000 个用户?

如何处理 Socket.io 和 Express 的会话?

如何处理 JSON 响应

如何处理 io.use 中间件来捕获客户端上的错误?

如何处理 terraform 进程崩溃并避免重试时资源泄漏?

如何处理Docker的错误消息request canceled:Docker代理问题