我们正在运行AWS Batch作业,这些作业启动Docker容器以运行Selenium和Chrome与python 3.6。 当我们将其设置为每个服务器运行多个容器时,作业通常会启动,运行几分钟,然后崩溃并显示chrome not reachable
:
File "/home/seluser/.local/lib/python3.6/site-packages/selenium/webdriver/remote/webdriver.py", line 597, in find_element_by_css_selector
return self.find_element(by=By.CSS_SELECTOR, value=css_selector)
File "/home/seluser/.local/lib/python3.6/site-packages/selenium/webdriver/remote/webdriver.py", line 966, in find_element
'value': value})['value']
File "/home/seluser/.local/lib/python3.6/site-packages/selenium/webdriver/remote/webdriver.py", line 320, in execute
self.error_handler.check_response(response)
File "/home/seluser/.local/lib/python3.6/site-packages/selenium/webdriver/remote/errorhandler.py", line 242, in check_response
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.WebDriverException: Message: chrome not reachable
(Session info: chrome=79.0.3945.117)
当我们更改 Batch 配置以确保每个服务器只有一个容器时,所有作业都已成功通过。
似乎在同一服务器上运行的多个作业相互干扰。它们应该隔离在自己的 Docker 容器中,那么会发生什么?我们如何找出问题所在并加以预防?
配置允许每个服务器有多个容器,以便我们可以在更少的服务器上运行更多作业。尝试访问 Chrome 时,许多作业使用此配置运行时都会崩溃。
批处理作业定义 - 每个服务器多个容器:
- 虚拟处理器 1
- 内存 3072 MiB
批处理计算环境 - 每个服务器多个容器:
- 最小 vCPU 数 0
- 所需的 vCPU 0
- 最大 vCPU 数 20
- 最佳实例类型
- 分配策略BEST_FIT
允许每个服务器使用单个容器的配置。所有工作都成功,但我们需要更多的服务器。
批处理作业定义 - 每个服务器一个容器:
- 虚拟处理器 2
- 内存 7168 MiB
计算环境 - 每个服务器一个容器:
- 最小 vCPU 数 0
- 所需的 vCPU 0
- 最大 vCPU 数 20
- 实例规格 m4.large
- 分配策略BEST_FIT
这会强制每个服务器使用一个容器,因为 m4.large 有 2 个 vCPU,并且作业定义指定了 2 个 vCPU。
AWS Batch 环境:ECS Docker:版本 18.09.9-ce,内部版本 039a7df
这些是 ECS 运行容器时使用的标志:
root 4824 1 8 19:04 ? 00:00:39 /usr/bin/dockerd
--default-ulimit nofile=1024:4096 --storage-driver devicemapper
--storage-opt dm.thinpooldev=/dev/mapper/docker-docker--pool
--storage-opt dm.use_deferred_removal=true --storage-opt dm.use_deferred_deletion=true
--storage-opt dm.fs=ext4 --storage-opt dm.use_deferred_deletion=true
以下是我们如何设置硒/铬:
import pyvirtualdisplay
from selenium import webdriver
pyvirtualdisplay.Display(visible=False, size=(1900, 1200))
options = webdriver.ChromeOptions()
prefs = {}
prefs["download.default_directory"] = self.download_dir
prefs["plugins.always_open_pdf_externally"] = True
prefs["profile.default_content_setting_values.automatic_downloads"] = 1
prefs["plugins.plugins_list"] = [{"enabled": False, "name": "Chrome PDF Viewer"}]
options.add_experimental_option("prefs", prefs)
options.add_argument("--disable-dev-shm-usage")
options.add_argument("--no-sandbox")
driver = webdriver.Chrome(
chrome_options=self._options(),
service_log_path=os.path.join(config.WORKING_DIRECTORY, "driver.log"))
我们已经尝试过但现在未使用的其他开关:
--headless
- 改用 pyvirtualdisplay 来解决与等待文件以无头 chrome 显示download_dir相关的超时
问题--disable-gpu
- 不适用,因为我们在 Linux 上运行--disable-setuid-sandbox
- 与--no-sandbox
重叠
问题是 AWS Batch 创建了具有host
网络的 docker 容器,当我们尝试运行多个 Xvfb 实例时,这会导致端口冲突。
更多详情:
http://elementalselenium.com/tips/38-headless 听起来像我们看到的:
如果您在同一时间跨不同版本无头运行测试 时间(例如,并行(在您的 CI 服务器上,然后作业将开始 意外中断。这是因为显示端口与 Xvfb(例如,两个或多个 Xvfb 会话尝试在同一设备上运行 同时显示端口(。
https://forums.aws.amazon.com/thread.jspa?threadID=254487
AWS Batch 通过 ECS 代理与计算资源通信,该代理 被指示在网络模式设置为"主机"的情况下启动作业,就像您一样 已经确定。目前,该服务不适用于运行作业 正在侦听容器中的外部网络请求 实例。
https://docs.docker.com/network/host/
如果对容器使用主机网络模式,则该容器的 网络堆栈未与 Docker 主机(容器(隔离 共享主机的网络命名空间(,并且容器不共享 分配自己的 IP 地址。例如,如果您运行一个容器 绑定到端口 80 并且您使用主机网络,容器的 应用程序在主机 IP 地址上的端口 80 上可用。
从man Xserver
:
:d播放号码 X 服务器作为给定的显示编号运行,默认情况下 为 0。 如果多个 X 服务器要同时在 主机,每个主机都必须具有唯一的显示编号。
我们使用PyVirtualDisplay来包装Xvfb。但是 PyVirtualDisplay 在启动 Xvfb 时不会添加显示参数(即 :123(。我尝试添加check_startup=True
,但失败了XStartTimeoutError('No display number returned by X server',)
xvfbwrapper"随机选择一个显示号码,并试图获取这个号码的锁"。Xvfb 命令行看起来像 Xvfb :35877838 -screen 0 1900x1200x24
使用此配置,我们成功地运行了每个服务器具有多个容器的作业。