与多个 Chrome Docker 容器的 Websocket 通信
Websocket communication with multiple Chrome Docker containers
我有一个 Chrome 容器(使用 this Dockerfile 部署),它根据 App 容器的请求呈现页面。
基本流程是:
- 应用向 Chrome 发送一个 http 请求,并作为响应接收一个 websocket url 以供使用(例如
ws://chrome.example.com:9222/devtools/browser/13400ef6-648b-4618-8e4c-b5c73db2a122
)
- App 然后使用该 websocket url 与 Chrome 进一步通信并接收呈现的页面。我正在使用 puppeteer library 连接到 Chrome 实例并与之通信,使用
puppeteer.connect({ browserWSEndpoint: webSocketUrl })
;
对于单个 Chrome 容器,这非常有效。
但我正在尝试扩大规模以在 Docker 群中拥有多个 Chrome 容器。
问题是,我认为,App 收到的 websocket url 特定于那个特定 Chrome 容器中的实例 运行,所以当它被 App 使用时(现在有多个 Chrome 容器),来自 App 的 websocket 请求不一定会路由到正确的 Chrome 容器。
处理这个问题的最佳方法是什么?
您的基本设计是正确的,但您遇到的问题是会话“粘性”。但是,与其尝试将 re-route 后续请求返回到适当的机器,不如寻找一种方法来避免 "pre" 请求。
最好的方法是让您的 Chrome docker 图片 man-in-the-middle 所有 http“升级”请求。这个 http 操作是所有 WebSocket 连接在更改协议之前发出的,包括 puppeteer 库(它只是一个 WebSocket 客户端 under-the-hood)。这样做也将避免 pre-connect 调用的需要,因为对 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);
这种方法还有其他好处:您可以限制诸如并发之类的事情,甚至可以稍后将脚本注入 运行。这些需要更多的准备和准备,但总体思路保持不变。这也使 load-balancing 变得微不足道,因为不需要使路由变得粘滞。
如果这是您有兴趣实现的东西,那么在 browserless repo. It even allows for things like concurrency limitations, session time limitations, and includes a feature-rich IDE. You can find more docs on that project here 中大部分工作都已为您完成。
我有一个 Chrome 容器(使用 this Dockerfile 部署),它根据 App 容器的请求呈现页面。
基本流程是:
- 应用向 Chrome 发送一个 http 请求,并作为响应接收一个 websocket url 以供使用(例如
ws://chrome.example.com:9222/devtools/browser/13400ef6-648b-4618-8e4c-b5c73db2a122
) - App 然后使用该 websocket url 与 Chrome 进一步通信并接收呈现的页面。我正在使用 puppeteer library 连接到 Chrome 实例并与之通信,使用
puppeteer.connect({ browserWSEndpoint: webSocketUrl })
;
对于单个 Chrome 容器,这非常有效。
但我正在尝试扩大规模以在 Docker 群中拥有多个 Chrome 容器。
问题是,我认为,App 收到的 websocket url 特定于那个特定 Chrome 容器中的实例 运行,所以当它被 App 使用时(现在有多个 Chrome 容器),来自 App 的 websocket 请求不一定会路由到正确的 Chrome 容器。
处理这个问题的最佳方法是什么?
您的基本设计是正确的,但您遇到的问题是会话“粘性”。但是,与其尝试将 re-route 后续请求返回到适当的机器,不如寻找一种方法来避免 "pre" 请求。
最好的方法是让您的 Chrome docker 图片 man-in-the-middle 所有 http“升级”请求。这个 http 操作是所有 WebSocket 连接在更改协议之前发出的,包括 puppeteer 库(它只是一个 WebSocket 客户端 under-the-hood)。这样做也将避免 pre-connect 调用的需要,因为对 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);
这种方法还有其他好处:您可以限制诸如并发之类的事情,甚至可以稍后将脚本注入 运行。这些需要更多的准备和准备,但总体思路保持不变。这也使 load-balancing 变得微不足道,因为不需要使路由变得粘滞。
如果这是您有兴趣实现的东西,那么在 browserless repo. It even allows for things like concurrency limitations, session time limitations, and includes a feature-rich IDE. You can find more docs on that project here 中大部分工作都已为您完成。