代码之家  ›  专栏  ›  技术社区  ›  drmrbrewer

Websocket与多个Chrome Docker容器的通信

  •  12
  • drmrbrewer  · 技术社区  · 7 年前

    我有一个Chrome容器(使用 this Dockerfile )根据应用程序容器的请求呈现页面。

    基本流程为:

    • 应用程序向Chrome发送http请求,作为响应,收到要使用的websocket url(例如。 ws://chrome.example.com:9222/devtools/browser/13400ef6-648b-4618-8e4c-b5c73db2a122 )
    • 然后,应用程序使用该websocket url与Chrome进一步通信,并接收呈现的页面。我正在使用 puppeteer library 要连接到Chrome实例并与之通信,请使用 puppeteer.connect({ browserWSEndpoint: webSocketUrl }) ;

    对于单个Chrome容器,这非常有效。

    但我正在尝试扩大规模,以便在Docker swarm中有多个Chrome容器。

    我认为,问题是,应用程序接收到的websocket url特定于在特定Chrome容器中运行的实例,因此当应用程序使用它时(现在有多个Chrome容器),来自应用程序的websocket请求不一定会路由到正确的Chrome容器。

    处理这个问题的最佳方法是什么?

    1 回复  |  直到 6 年前
        1
  •  14
  •   browserless    7 年前

    您的基本设计是正确的,但您遇到的问题是会话粘性。然而,我们应该寻找一种避免“pre”请求的方法,而不是尝试将后续请求重新路由回相应的机器。

    最好的方法是让您的Chrome docker image man位于所有http–upgrade–请求的中间。此http操作是所有WebSocket连接在更改协议之前发出的,包括Puppeter库(它只是一个隐藏的WebSocket客户端)。这样做还可以避免预连接调用,因为代理Chrome将在升级时发生,而不是公开应用程序要使用的URL。下面是一个使用 http-proxy 模块:

    const http = require('http');
    const httpProxy = require('http-proxy');
    
    const proxy = new httpProxy.createProxyServer();
    
    http
      .createServer()
      .on('upgrade', async(req, socket, head) => {
          const browser = await puppeteer.launch();
          const target = browser.wsEndpoint();
    
          proxyy.ws(req, socket, head, { target })
      })
      .listen(3000);
    

    这种方法还有其他好处:您可以限制并发性,甚至可以注入脚本以便稍后运行。这些需要更多的思考和准备,但总体思路保持不变。这也使得负载平衡变得微不足道,因为不需要使路由变得有粘性。

    如果这是您感兴趣的事情,那么在 browserless 回购。它甚至允许并发限制、会话时间限制和 includes a feature-rich IDE . 你可以找到更多 docs on that project here .