与多个Chrome Docker容器进行Websocket通信

drm*_*wer 12 google-chrome websocket docker puppeteer

我有一个Chrome容器(使用此Dockerfile部署),可以根据请求从App容器呈现页面.

基本流程是:

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

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

但我正在尝试扩展以在Docker群中拥有多个Chrome容器.

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

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

bro*_*ess 13

你的基本设计是正确的,但你遇到的问题是会话"粘性".但是,我们应该寻找一种避免"预先"请求的方法,而不是尝试将后续请求重新路由回适当的机器.

最好的方法是让你的Chrome docker图像为中间所有http"升级"请求.这个http动作是所有WebSocket连接在更改协议之前发出的,包括puppeteer库(它只是一个引擎盖下的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);
Run Code Online (Sandbox Code Playgroud)

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

如果你有兴趣实现这一点,那么所有的工作主要是在无浏览器仓库中完成的.它甚至允许诸如并发限制,会话时间限制之类的东西,并且包括功能丰富的IDE.您可以在此处找到有关该项目的更多文档.