适用于 Linux Chrome Docker 映像的 NodeJS Selenium WebDriver
2022-02-16
3563
我终其一生都搞不清楚如何创建一个轻量级的 Linux 容器,使用 Selenium WebDriver、Chrome 和 NodeJS 对网站执行测试。启动 ChromeDriver 时,我似乎总是遇到权限问题。
我还希望使用一个可以自动更新 ChromeDriver 的软件包,或者 - 同样 - 锁定 Chrome 以防止其自动更新。
我并不想运行 Selenium Grid - 只需要一个简单、轻量级的容器。
Dockerfile
# Use alpine-based NodeJS base image
FROM node:latest
#USER root
# Install latest stable Chrome
# https://gerg.dev/2021/06/making-chromedriver-and-chrome-versions-match-in-a-docker-image/
RUN echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" | \
tee -a /etc/apt/sources.list.d/google.list && \
wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | \
apt-key add - && \
apt-get update && \
apt-get install -y google-chrome-stable libxss1
# Determine major browser version
ARG BROWSER_MAJOR=$(google-chrome --version | sed 's/Google Chrome \([0-9]*\).*/\1/g')
# Install the Chromedriver version that corresponds to the installed major Chrome version
# https://blogs.sap.com/2020/12/01/ui5-testing-how-to-handle-chromedriver-update-in-docker-image/
RUN google-chrome --version | grep -oE "[0-9]{1,10}.[0-9]{1,10}.[0-9]{1,10}" > /tmp/chromebrowser-main-version.txt
RUN wget --no-verbose -O /tmp/latest_chromedriver_version.txt https://chromedriver.storage.googleapis.com/LATEST_RELEASE_$(cat /tmp/chromebrowser-main-version.txt)
RUN wget --no-verbose -O /tmp/chromedriver_linux64.zip https://chromedriver.storage.googleapis.com/$(cat /tmp/latest_chromedriver_version.txt)/chromedriver_linux64.zip && rm -rf /opt/selenium/chromedriver && unzip /tmp/chromedriver_linux64.zip -d /opt/selenium && rm /tmp/chromedriver_linux64.zip && mv /opt/selenium/chromedriver /opt/selenium/chromedriver-$(cat /tmp/latest_chromedriver_version.txt) && chmod 755 /opt/selenium/chromedriver-$(cat /tmp/latest_chromedriver_version.txt) && ln -fs /opt/selenium/chromedriver-$(cat /tmp/latest_chromedriver_version.txt) /usr/bin/chromedriver
# Set the variable for the container working directory
ARG WORK_DIRECTORY=/program
# Create app directory
RUN mkdir -p $WORK_DIRECTORY
WORKDIR $WORK_DIRECTORY
# Install npm packages (do this AFTER setting the working directory)
RUN npm config set unsafe-perm true
RUN npm i selenium-webdriver
ENV NODE_ENV=development NODE_PATH=$WORK_DIRECTORY
# Copy script to execute to working directory
COPY runtest.js .
EXPOSE 8080
# Execute the script in NodeJS
CMD ["node", "runtest.js"]
runtest.js
const { Builder } = require('selenium-webdriver');
const { Options } = require('selenium-webdriver/chrome');
(async function hello() {
//Browser Setup
let builder = new Builder().forBrowser('chrome');
let options = new Options();
options.headless(); // run headless Chrome
options.excludeSwitches(['enable-logging']); // disable 'DevTools listening on...'
const driver = await builder.setChromeOptions(options).build();
console.log('Hello World!');
})();
我当前在构建和运行此映像时遇到的错误是:
/program/node_modules/selenium-webdriver/lib/error.js:522
let err = new ctor(data.message)
^
WebDriverError: unknown error: Chrome failed to start: crashed.
(unknown error: DevToolsActivePort file doesn't exist)
(The process started from chrome location /usr/bin/google-chrome is no longer running, so ChromeDriver is assuming that Chrome has crashed.)
at Object.throwDecodedError (/program/node_modules/selenium-webdriver/lib/error.js:522:15)
at parseHttpResponse (/program/node_modules/selenium-webdriver/lib/http.js:548:13)
at Executor.execute (/program/node_modules/selenium-webdriver/lib/http.js:474:28)
2个回答
添加
--no-sandbox
开关解决了该问题。我意识到从安全角度来看这是不可取的;但是,我控制容器及其发生的情况,因此我至少认为这是一条合理的途径。如果有其他建议可以解决我原始帖子中的错误,请告诉我。如果
Dockerfile
中有任何可以修剪或修改以变得更好的东西,也请提出建议。
回顾一下我想要实现的目标:
-
从基本 NodeJS 容器开始。我选择了基于 alpine 的
node:latest
映像。 - 安装最新的稳定 Chrome。
- 安装与已安装的主要 Chrome 版本相对应的 Chromedriver 版本。
-
安装必要的 npm 依赖项。在我的情况下,那只是
selenium-webdriver
。我在我的 Dockerfile 中这样做了,但如果我有更多依赖项,我会改为设置一个 package.json 文件,然后在 Dockerfile 中运行npm i
。 - 执行一个简单的基于 NodeJS 的 Selenium 测试,以导航到网页、查找元素并将有关它的信息记录到控制台。
Dockerfile
# 1) Use alpine-based NodeJS base image
FROM node:latest
# 2) Install latest stable Chrome
# https://gerg.dev/2021/06/making-chromedriver-and-chrome-versions-match-in-a-docker-image/
RUN echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" | \
tee -a /etc/apt/sources.list.d/google.list && \
wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | \
apt-key add - && \
apt-get update && \
apt-get install -y google-chrome-stable libxss1
# 3) Install the Chromedriver version that corresponds to the installed major Chrome version
# https://blogs.sap.com/2020/12/01/ui5-testing-how-to-handle-chromedriver-update-in-docker-image/
RUN google-chrome --version | grep -oE "[0-9]{1,10}.[0-9]{1,10}.[0-9]{1,10}" > /tmp/chromebrowser-main-version.txt
RUN wget --no-verbose -O /tmp/latest_chromedriver_version.txt https://chromedriver.storage.googleapis.com/LATEST_RELEASE_$(cat /tmp/chromebrowser-main-version.txt)
RUN wget --no-verbose -O /tmp/chromedriver_linux64.zip https://chromedriver.storage.googleapis.com/$(cat /tmp/latest_chromedriver_version.txt)/chromedriver_linux64.zip && rm -rf /opt/selenium/chromedriver && unzip /tmp/chromedriver_linux64.zip -d /opt/selenium && rm /tmp/chromedriver_linux64.zip && mv /opt/selenium/chromedriver /opt/selenium/chromedriver-$(cat /tmp/latest_chromedriver_version.txt) && chmod 755 /opt/selenium/chromedriver-$(cat /tmp/latest_chromedriver_version.txt) && ln -fs /opt/selenium/chromedriver-$(cat /tmp/latest_chromedriver_version.txt) /usr/bin/chromedriver
# 4) Set the variable for the container working directory & create the working directory
ARG WORK_DIRECTORY=/program
RUN mkdir -p $WORK_DIRECTORY
WORKDIR $WORK_DIRECTORY
# 5) Install npm packages (do this AFTER setting the working directory)
RUN npm config set unsafe-perm true
RUN npm i selenium-webdriver
ENV NODE_ENV=development NODE_PATH=$WORK_DIRECTORY
# 6) Copy script to execute to working directory
COPY runtest.js .
EXPOSE 8080
# 7) Execute the script in NodeJS
CMD ["node", "runtest.js"]
runtest.js
const { Builder, By } = require('selenium-webdriver');
const { Options } = require('selenium-webdriver/chrome');
(async function hello() {
let driver;
try {
//Browser Setup
let builder = new Builder().forBrowser('chrome');
let options = new Options();
options.headless(); // run headless Chrome
options.excludeSwitches(['enable-logging']); // disable 'DevTools listening on...'
options.addArguments(['--no-sandbox']); // not an advised flag but eliminates "DevToolsActivePort file doesn't exist" error.
driver = await builder.setChromeOptions(options).build();
// Navigate to Google and get the "Google Search" button text.
await driver.get('https://www.google.com');
const btnText = await driver.findElement(By.name('btnK')).getAttribute('value');
console.log(`Google button text: ${btnText}`);
} catch (e) {
console.log(e);
} finally {
if (driver) {
await driver.close(); // helps chromedriver shut down cleanly and delete the "scoped_dir" temp directories that eventually fill up the harddrive.
await driver.quit();
}
}
})();
执行
docker build -t "node-chrome" -f Dockerfile .
:
在 Docker Desktop 中运行图像会显示按钮文本:
这表明此设置正在运行。
Simon
2022-02-23
不,所以沙盒被认为是不安全的。我发现的解决方法是以非 root 身份运行 docker。
因此,在
CMD
之前,您应该添加
USER node
然后,您还必须在特权模式下运行 docker (
--privileged
)
LowMan
2023-05-29